当前位置: 首页 > news >正文

从零实现一个可加减的Matrix矩阵类:支持索引、相等判断与实际场景应用

在这里插入图片描述

摘要

本文基于你给出的一段矩阵类(Matrix)片段,整理并补全为一个可运行、易理解、有实际场景的实现。文章采用接近日常交流的口吻,会讲清楚为什么要这样实现、每个方法的代码解析、以及用在真实场景中的例子(例如图像处理、数据表运算、线性代数小工具等)。最后给出示例测试、运行结果、时间复杂度与空间复杂度分析,并做总结。

描述

你给出的代码片段里包含对矩阵按位置赋值(支持索引与二维索引)、矩阵相等判断、矩阵相加和相减的若干方法,但格式上有错乱和不完整。我会把这些功能整理成一个完整的 Matrix 类,保持接口直观(支持 m[i]m[i,j] 赋值与读取;支持 ==+-),并把内部实现写清楚、注释说明每一步的理由和潜在坑(比如深拷贝、维度检测、错误处理等)。

我们会用一个常见的实际场景来驱动这段代码:假设你在做一款小工具,用于处理表格数据或灰度图像(图像可以看成矩阵)——例如对两张同尺寸图像做差分检测、对两个实验数据表做元素级相加以得到合并结果,或者比较两个矩阵是否一致以校验数据传输。文章会给出示例代码和运行结果。

题解答案

下面是我整理并实现的 Matrix 类,包含:

  • 构造(__init__
  • 可读写索引(__getitem__, __setitem__,支持单索引和双索引)
  • 相等比较(__eq__
  • 加法(__add__
  • 减法(__sub__
  • 简单的字符串表示(__str__

完整代码如下(可直接复制运行):

import copyclass Matrix:"""简单的矩阵类,支持按元素访问、赋值,支持 ==、+、- 操作。行、列索引在接口上使用 1-based(与题目代码一致),内部使用 0-based 存储。"""def __init__(self, rows: int, cols: int, fill: float = 0.0):if rows <= 0 or cols <= 0:raise ValueError("rows and cols must be positive integers")self.row = rowsself.column = cols# 内部存储为 list of lists,0-basedself.matrix = [[copy.deepcopy(fill) for _ in range(cols)] for _ in range(rows)]@propertydef shape(self):return (self.row, self.column)def __getitem__(self, index):"""支持两种索引方式:m[i] -> 返回第 i 行(1-based),作为列表(浅拷贝)m[i, j] -> 返回第 i 行第 j 列元素(1-based)"""if isinstance(index, int):i = indexif i < 1 or i > self.row:raise IndexError("row index out of range (1-based)")# 返回一份浅拷贝,避免外部直接修改内部结构return self.matrix[i-1].copy()elif isinstance(index, tuple) and len(index) == 2:i, j = indexif i < 1 or i > self.row or j < 1 or j > self.column:raise IndexError("index out of range (1-based)")return self.matrix[i-1][j-1]else:raise TypeError("index must be int or tuple of two ints")def __setitem__(self, index, value):"""支持:m[i] = a_list -> 将第 i 行全部替换(会进行深拷贝)m[i,j] = value -> 将单个元素赋值"""if isinstance(index, int):i = indexif not isinstance(value, (list, tuple)):raise TypeError("assigning to a row requires a list/tuple")if len(value) != self.column:raise ValueError("assigned row length does not match number of columns")if i < 1 or i > self.row:raise IndexError("row index out of range (1-based)")# 深拷贝一份,避免外部引用影响内部self.matrix[i-1] = copy.deepcopy(list(value))elif isinstance(index, tuple) and len(index) == 2:i, j = indexif i < 1 or i > self.row or j < 1 or j > self.column:raise IndexError("index out of range (1-based)")self.matrix[i-1][j-1] = valueelse:raise TypeError("index must be int or tuple of two ints")def __eq__(self, B):"""判断两个矩阵是否相等(元素逐一比较)。需要 B 是 Matrix 类型或具有 shape 和 matrix 属性的对象。"""if not isinstance(B, Matrix):return Falseif self.shape != B.shape:return Falsefor i in range(self.row):for j in range(self.column):if self.matrix[i][j] != B.matrix[i][j]:return Falsereturn Truedef __add__(self, B):"""矩阵逐元素相加,返回新的 Matrix 对象。如果维度不同,抛出 ValueError。"""if not isinstance(B, Matrix):raise TypeError("Can only add Matrix with Matrix")if self.shape != B.shape:raise ValueError("shape mismatch: cannot add matrices with different shape")M = Matrix(self.row, self.column)for i in range(self.row):for j in range(self.column):M.matrix[i][j] = self.matrix[i][j] + B.matrix[i][j]return Mdef __sub__(self, B):"""矩阵逐元素相减,返回新的 Matrix 对象。如果维度不同,抛出 ValueError。"""if not isinstance(B, Matrix):raise TypeError("Can only subtract Matrix with Matrix")if self.shape != B.shape:raise ValueError("shape mismatch: cannot subtract matrices with different shape")M = Matrix(self.row, self.column)for i in range(self.row):for j in range(self.column):M.matrix[i][j] = self.matrix[i][j] - B.matrix[i][j]return Mdef __str__(self):lines = []for row in self.matrix:lines.append("[" + ", ".join(str(x) for x in row) + "]")return "\n".join(lines)# 为了方便调试,提供一个复制方法def copy(self):M = Matrix(self.row, self.column)M.matrix = copy.deepcopy(self.matrix)return M

题解代码分析

接下来逐一解释上面代码的关键点和设计考虑。

  1. 构造 __init__

    • 要求 rows 和 cols 为正整数,避免不合理构造。
    • 内部用 self.matrix 存列表的列表。使用 copy.deepcopy(fill) 保证如果 fill 是可变对象也被安全复制(虽然通常是数值)。
    • 设计为 1-based 索引对外接口(和题目保持一致),但内部仍用 0-based 列表索引。
  2. shape 属性:

    • 返回 (rows, cols),便于外部检查维度相等。
  3. __getitem__

    • 支持 m[i](返回第 i 行)与 m[i, j](返回第 i 行第 j 列)这两种常见访问方式。
    • m[i] 返回行时用 .copy(),避免用户拿到引用后直接改动 self.matrix 的内部数据(如果需要改动行,建议使用 m[i] = ... 显式赋值)。
    • 对索引超界进行检查并抛出 IndexError
  4. __setitem__

    • 两种赋值方式都支持:按行赋值和按元素赋值。
    • 按行赋值时,要求提供的 value 是 list 或 tuple,并且长度须匹配列数,并深拷贝以防止后续外部修改影响内部矩阵。
    • 按元素赋值时,直接替换对应位置的值。
    • 设计上明确区分了错误类型(TypeErrorValueErrorIndexError),便于上层调用者捕获与调试。
  5. __eq__

    • 首先检查对象类型是否为 Matrix(或你可以放宽要求,但这里做严格检查),然后检查 shape,最后逐元素比较。只要有一个元素不同则返回 False,否则 True
  6. __add____sub__

    • 这里都要求另一个操作数是 Matrix,并且维度相同。返回新的 Matrix 对象而不是修改原矩阵(函数式风格,更安全)。
    • 在内部通过循环逐元素赋值。如果遇到维度不同,抛出 ValueError,比返回字符串更 Pythonic、更利于异常处理与调试。
  7. __str__

    • 提供一个简单的行格式打印,便于调试与展示。
  8. copy

    • 提供深拷贝的方法,方便需要保存快照的场景(例如在算法中保存中间状态)。

示例测试及结果

下面给出几个实际示例,演示如何在常见场景中使用该类,并展示运行结果。

示例 A:基础操作(构造、赋值、读取、打印)

# 构造 3x3 矩阵
A = Matrix(3, 3, fill=0)
# 按元素赋值(1-based)
A[1,1] = 10
A[1,2] = 20
A[3,3] = 30
# 按行赋值
A[2] = [1, 2, 3]
print("A =")
print(A)

运行结果(打印):

A =
[10, 20, 0]
[1, 2, 3]
[0, 0, 30]

示例 B:矩阵相加与相减(模拟两张同尺寸灰度图像的像素相减)

M1 = Matrix(2, 2)
M1[1] = [100, 120]
M1[2] = [90, 110]M2 = Matrix(2, 2)
M2[1] = [95, 125]
M2[2] = [88, 115]sum_mat = M1 + M2
diff_mat = M1 - M2print("M1 + M2 =")
print(sum_mat)
print("M1 - M2 =")
print(diff_mat)

运行结果:

M1 + M2 =
[195, 245]
[178, 225]
M1 - M2 =
[5, -5]
[2, -5]

这里 “差分” M1 - M2 能直接反映像素亮度的变化(比如在图像差分检测中可用于运动检测或变更检测)。

示例 C:相等比较(校验数据一致性)

A = Matrix(2,2)
A[1] = [1,2]
A[2] = [3,4]B = A.copy()
print("A == B ?", A == B)  # TrueB[2,2] = 999
print("修改后 A == B ?", A == B)  # False

运行结果:

A == B ? True
修改后 A == B ? False

示例 D:错误处理示例(不同维度相加)

X = Matrix(2,3)
Y = Matrix(3,2)
try:Z = X + Y
except Exception as e:print("错误:", e)

输出:

错误: shape mismatch: cannot add matrices with different shape

时间复杂度

对于我们实现的主要操作,复杂度如下(设矩阵为 m x n):

  • 构造(__init__):需要创建 m*n 个元素 -> 时间复杂度 (O(mn))。
  • 读取单元素(__getitem__(i,j)):常数时间 -> (O(1))。
  • 读取整行(__getitem__i):行复制 -> (O(n))(复制一行)。
  • 行赋值(__setitem__i = list):需要复制一行 -> (O(n))。
  • 单元素赋值:常数时间 (O(1))。
  • 相等比较(__eq__):需要逐元素比较 -> 最坏 (O(mn))。
  • 相加 / 相减(__add__ / __sub__):逐元素处理并生成新矩阵 -> (O(mn))。

空间复杂度

  • 单个 Matrix 对象占用空间与元素数量成正比 -> (O(mn))。
  • 相加/相减会创建一个新的矩阵,临时在内存中同时存在两个(或更多)矩阵,因此在执行 C = A + B 时额外需要 (O(mn)) 的空间(结果矩阵),加上输入矩阵的空间总共 (O(mn))(常量因子不同,但渐进相同)。
  • 行赋值或复制会产生额外的行长度拷贝(长度为 n),所以局部峰值也可能略高于 (O(mn)),但总体仍是 (O(mn))。

与实际场景结合(举几个贴近日常的应用场景)

下面给出三个典型、容易理解的现实例子,说明这个 Matrix 类如何被用到实际项目中。

图像差分(变更检测)

  • 场景描述:你在做一个简易监控系统,摄像头每隔一段时间截取灰度图(转换成二维矩阵)。你想检测画面是否有明显变化(有人走进镜头),可以对连续两帧做像素级差分(逐元素相减),然后统计差分矩阵中绝对值超过阈值的像素数。
  • 为什么用这里的实现:本类的逐元素相减直接给出差分矩阵,易于后续统计与阈值处理。

表格数据合并(实验数据求和)

  • 场景描述:两位同学进行了同样的实验并录入了二维结果(每行是实验样本,每列是不同指标)。现在需要把两组结果逐元素相加得到总和(例如合并实验次数或累计测量值)。
  • 为什么用这里的实现:矩阵相加语义明确,并在维度不匹配时抛出异常,提醒数据录入异常或预处理不足。

单元测试与数据校验(数据传输完整性)

  • 场景描述:后台服务把矩阵数据从服务A发送给服务B,B端收到数据后要验证是否与发送端一致。使用 == 比较矩阵内容可以快速判断数据是否被篡改或传输错误。
  • 为什么用这里的实现:__eq__ 做了逐元素检查,简单可靠。

总结

  • 我把你给出的片段整理成了一个完整的 Matrix 类,实现了按行与按元素读写、相等检测、相加与相减等常用操作,并在接口中采用 1-based 索引以和你的原片段一致。
  • 代码中注重错误处理(抛出明确异常)和拷贝策略(浅拷贝行返回、深拷贝赋值)以避免常见的引用陷阱。
  • 示例覆盖了基础使用、相加相减、相等校验以及错误处理,并演示了和现实场景(图像差分、数据合并、校验)的结合。
  • 算法复杂度方面,相等比较/相加/相减均为 (O(mn)),空间复杂度主要由矩阵大小决定,同样为 (O(mn))。

如果你愿意,我可以继续:

  • 把索引改为 0-based,或同时支持 0-based/1-based;
  • 增加矩阵乘法、转置、按行/列求和等功能;
  • 把数值类型限制为 int/float 并增加异常更严格的校验;
  • 或把矩阵实现优化为基于 NumPy 的实现以得到更高性能(如果你想用第三方库的话)。
http://www.dtcms.com/a/529111.html

相关文章:

  • CUDA-GDB(5)——内核聚焦
  • 51c大模型~合集29
  • 543刷题记录
  • 上海门户网站建设公司logo在线
  • 【FPGA】三八译码器——仿真验证
  • 哪些网站可以做设计方案网站建设 客户
  • h5游戏免费下载:堆雪人
  • UltraISO制作系统启动盘
  • 未来之窗昭和仙君(三十六)抽奖随机算法前端——东方仙盟筑基期
  • wordpress网站添加密码访问17网站一起做网店广
  • 惠州网站建设制作志愿服务网站建设中标公告
  • 资料分析-年均与乘积增长率
  • 视频网站用什么做的济南网站建设山东聚搜网推荐
  • Minecraft合集
  • 公司网页网站建设sae wordpress 图片
  • 网站建设读后感为什么网页不能打开建设银行网站
  • 百度网站流量查询南京房地产网站建设
  • 南安梅山建设银行网站长春快速建站模板
  • CSMA/CA 协议和CSMA/CD的区别
  • 网络自动化:Ansible/Netmiko 网络设备批量配置与管理
  • 探索聊天机器人系统提示的秘密[特殊字符]
  • 接近光速运动下的光速不变性:基于张祥前统一场论的推导与验证
  • 固始网站制作四川德充建设集团有限公司网站
  • STM32G474单片机开发入门(二十七)HRTIME高精度定时器的PWM(50KHZ)输出实战
  • Windows磁盘占用率高解决记录
  • 泛用性而言,系统分析师 与 信息系统项目管理工程师 比较
  • 网站程序国内 wordpress主题
  • 太仓公司网站建设电话天津企业网站建设方案
  • AI 浏览器技术趋势分析:Perplexity Comet 的创新与早期用户激励机制探讨
  • 4.基础开发工具(一)