从矩阵基础到代码实现:彻底理解广义矩阵乘法
从矩阵基础到代码实现:彻底理解广义矩阵乘法
作为编程新手,理解矩阵和矩阵乘法是学习许多算法和数据结构的基础。本文将从最基础的矩阵概念开始,逐步引导你理解一段 C++ 代码,该代码定义了一个矩阵结构体并实现了一种特殊的矩阵乘法 —— 广义矩阵乘积。通过本文的学习,你将不仅掌握矩阵的基本概念和运算规则,还能理解如何用 C++ 代码实现这些概念,并将其应用于解决实际问题。
一、矩阵的基本概念
1.1 什么是矩阵?
矩阵是数学中一种重要的数据结构,它由行(row)和列(column)组成,是一个二维的数值数组。简单来说,矩阵就是将数字按行和列排列成的矩形表格。例如:
\(A = \begin{bmatrix} 1 & 2 & 3 \\ 4 & 5 & 6 \end{bmatrix}\)
这是一个 2 行 3 列的矩阵,我们称它为 2×3 矩阵。矩阵中的每个数字称为矩阵的元素(element)或项(entry)。矩阵通常用大写字母表示,如 A、B、C 等,而矩阵中的元素则用对应的小写字母并加上行和列的索引来表示,如 aij表示矩阵 A 中第 i 行第 j 列的元素。
1.2 矩阵的基本术语
-
维度(Dimension):矩阵的维度由它包含的行数和列数决定。一个 m 行 n 列的矩阵称为 m×n 矩阵。
-
行矩阵(Row Matrix):只有一行的矩阵,例如 [1 2 3]。
-
列矩阵(Column Matrix):只有一列的矩阵,例如:
\(\begin{bmatrix} 1 \\ 2 \\ 3 \end{bmatrix}\)
-
方阵(Square Matrix):行数和列数相等的矩阵,例如 3×3 矩阵。
-
零矩阵(Zero Matrix):所有元素都为 0 的矩阵。
-
单位矩阵(Identity Matrix):主对角线上的元素全为 1,其余元素全为 0 的方阵。例如 3×3 单位矩阵:
\(I = \begin{bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end{bmatrix}\)
1.3 矩阵的运算
矩阵可以进行多种运算,包括加法、数乘和乘法等。这些运算都有特定的规则和条件:
-
矩阵加法:两个矩阵必须具有相同的维度才能相加,结果矩阵的每个元素是原矩阵对应位置元素的和。
-
数乘:一个标量(普通数字)与矩阵相乘,结果矩阵的每个元素是原矩阵对应元素与该标量的乘积。
-
矩阵乘法:两个矩阵 A 和 B 可以相乘的条件是 A 的列数等于 B 的行数。结果矩阵 C 的每个元素 Cij等于 A 的第 i 行与 B 的第 j 列对应元素乘积的和。
二、矩阵乘法详解
2.1 矩阵乘法的基本规则
矩阵乘法是线性代数中的核心运算,也是理解本文代码的关键。让我们详细了解矩阵乘法的规则:
条件:矩阵 A(m×n)和矩阵 B(n×p)可以相乘,结果矩阵 C 是 m×p 的矩阵。
计算方式:结果矩阵 C 中的元素 Cij由以下公式计算:
\(C_{ij} = \sum_{k=1}^{n} A_{ik} \times B_{kj}\)
这表示 C 的第 i 行第 j 列元素是 A 的第 i 行与 B 的第 j 列对应元素相乘后相加的结果。
示例:
假设有两个矩阵 A 和 B:
\(A = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}, \quad B = \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix}\)
它们的乘积 C = AB 计算如下:
\(C_{11} = 1×5 + 2×7 = 5 + 14 = 19 \\ C_{12} = 1×6 + 2×8 = 6 + 16 = 22 \\ C_{21} = 3×5 + 4×7 = 15 + 28 = 43 \\ C_{22} = 3×6 + 4×8 = 18 + 32 = 50 \\\)
结果矩阵 C 为:
\(C = \begin{bmatrix} 19 & 22 \\ 43 & 50 \end{bmatrix}\)
2.2 矩阵乘法的性质
矩阵乘法具有以下重要性质:
-
结合律:(AB)C = A(BC)
-
分配律:A(B + C) = AB + AC,(B + C)A = BA + CA
-
不满足交换律:一般情况下,AB ≠ BA
-
与单位矩阵相乘:AI = IA = A
2.3 广义矩阵乘法
本文代码实现的是一种特殊的矩阵乘法,称为广义矩阵乘法。与标准矩阵乘法不同,广义矩阵乘法使用不同的二元运算符来替代传统的乘法和加法。
在本文的代码中,广义矩阵乘法的定义是:
\(C_{ij} = \max_{k} (A_{ik} + B_{kj})\)
即,结果矩阵 C 的每个元素是 A 的第 i 行与 B 的第 j 列对应元素相加后的最大值,而不是传统的乘积之和。这种运算在某些算法问题中特别有用,例如求最长路径问题。
三、C++ 代码详解
现在我们来详细分析你提供的 C++ 代码,理解每个部分的作用和运行逻辑。
3.1 结构体定义
struct matrix{
int g[2][2]; // 存储2×2矩阵的二维数组
解释:
-
struct关键字用于定义一个结构体类型。结构体是 C++ 中用户自定义的数据类型,可以包含不同类型的成员变量。 -
matrix是结构体的名称。 -
g[2][2]是一个 2 行 2 列的二维数组,用于存储矩阵的元素。g[i][j]表示矩阵第 i 行第 j 列的元素。
3.2 运算符重载:广义矩阵乘法
matrix operator*(matrix b){ //广义矩阵积
matrix t; memset(t.g,-0x3f,sizeof(t.g));
解释:
-
operator*是运算符重载,允许使用*运算符对matrix类型的对象进行操作。 -
matrix operator*(matrix b)声明了一个成员函数,该函数定义了matrix类型对象与另一个matrix对象b相乘的行为。 -
matrix t创建了一个临时矩阵t,用于存储乘法结果。 -
memset(t.g,-0x3f,sizeof(t.g))将矩阵t的所有元素初始化为 - 0x3f3f3f3f(约等于 - 1061109567)。这是一个非常小的数,作为初始值以便后续的最大值比较。
为什么初始化为 - 0x3f3f3f3f?
因为我们要在后续计算中取最大值,初始值必须足够小,确保第一个比较对象(不管是什么)都会比它大,从而正确更新结果。-0x3f3f3f3f 是一个常用的 “负无穷” 替代值,因为它的十六进制表示全为 0x3f 重复,而memset按字节填充,所以用-0x3f填充整个数组会得到一个非常小的数。
3.3 三重循环实现广义矩阵乘法
for(int i=0; i<=1; ++i)
for(int j=0; j<=1; ++j)
for(int k=0; k<=1; ++k)
t.g[i][j]=max(t.g[i][j],g[i][k]+b.g[k][j]);
return t;
}
解释:
-
外层三层循环遍历所有可能的
i、j、k组合。i和j用于遍历结果矩阵t的行和列,k用于遍历中间索引。 -
对于每个位置
(i,j),计算g[i][k] + b.g[k][j]的最大值,其中k从 0 到 1。这相当于将传统矩阵乘法中的乘积替换为加法,将求和替换为求最大值。 -
t.g[i][j] = max(t.g[i][j], g[i][k] + b.g[k][j])确保每个位置的值是所有可能的k路径中的最大值。
三重循环的顺序:
循环的顺序是i(行)、j(列)、k(中间索引),这与标准矩阵乘法的顺序相同。这是因为矩阵乘法的数学定义要求遍历所有可能的中间元素,以计算正确的行和列组合。
3.4 结构体数组声明
}mt[N],tr[N<<2];
解释:
-
mt[N]声明了一个名为mt的matrix类型数组,包含N个元素。这个数组可能用于存储原始矩阵数据。 -
tr[N<<2]声明了另一个matrix类型数组tr,其大小为N<<2。N<<2是按位左移操作,相当于N*4。这种大小通常用于线段树(一种数据结构),因为线段树通常需要 4 倍于原始数据大小的空间。
四、代码运行逻辑分析
为了更好地理解代码的运行逻辑,我们可以通过一个具体的例子来模拟代码的执行过程。
4.1 示例矩阵
假设有两个矩阵 A 和 B:
\(A = \begin{bmatrix} 1 & 2 \\ 3 & 4 \end{bmatrix}, \quad B = \begin{bmatrix} 5 & 6 \\ 7 & 8 \end{bmatrix}\)
4.2 广义矩阵乘法计算过程
计算 C = A * B 的过程如下:
初始化矩阵 t:
\(t = \begin{bmatrix} -∞ & -∞ \\ -∞ & -∞ \end{bmatrix}\)
计算 t.g [0][0]:
-
k=0: 1 + 5 = 6 → max(-∞, 6) = 6
-
k=1: 2 + 7 = 9 → max(6, 9) = 9
→ t.g[0][0] = 9→ t.g[0][0] = 9
计算 t.g [0][1]:
-
k=0: 1 + 6 = 7 → max(-∞, 7) = 7
-
k=1: 2 + 8 = 10 → max(7, 10) = 10
→ t.g[0][1] = 10→ t.g[0][1] = 10
计算 t.g [1][0]:
-
k=0: 3 + 5 = 8 → max(-∞, 8) = 8
-
k=1: 4 + 7 = 11 → max(8, 11) = 11
→ t.g[1][0] = 11→ t.g[1][0] = 11
计算 t.g [1][1]:
-
k=0: 3 + 6 = 9 → max(-∞, 9) = 9
-
k=1: 4 + 8 = 12 → max(9, 12) = 12
→ t.g[1][1] = 12→ t.g[1][1] = 12
最终结果矩阵 t:
\(t = \begin{bmatrix} 9 & 10 \\ 11 & 12 \end{bmatrix}\)
4.3 与标准矩阵乘法的对比
如果使用标准矩阵乘法计算 A 和 B 的乘积,结果将是:
\(C = \begin{bmatrix} 19 & 22 \\ 43 & 50 \end{bmatrix}\)
这与广义矩阵乘法的结果明显不同,说明两种运算的应用场景也不同。
五、广义矩阵乘法的应用场景
你可能会问,这种广义矩阵乘法有什么实际用途呢?以下是一些常见的应用场景:
5.1 最长路径问题
在图论中,广义矩阵乘法可以用于求解图中经过若干条边的最长路径。假设有一个图,其邻接矩阵 A 中 A [i][j] 表示从节点 i 到节点 j 的边权。使用标准矩阵乘法,A²[i][j] 表示从 i 到 j 恰好经过 2 条边的路径数目;而使用广义矩阵乘法,A²[i][j] 则表示从 i 到 j 恰好经过 2 条边的最长路径长度。
5.2 动态规划优化
广义矩阵乘法可以用于优化某些动态规划问题。例如,对于斐波那契数列这样的递推关系,可以通过构造适当的转移矩阵,利用矩阵快速幂将时间复杂度从 O (n) 优化到 O (log n)。
5.3 状态转移
在状态转移问题中,矩阵乘法可以表示状态之间的转移关系。通过广义矩阵乘法,可以找到最优的状态转移路径,例如在机器人路径规划或状态机设计中。
六、矩阵快速幂
矩阵快速幂是将快速幂算法应用于矩阵乘法的一种技术,通常用于高效计算矩阵的高次幂。这在解决递推关系或动态规划问题时非常有用。
6.1 矩阵快速幂的实现思路
矩阵快速幂的基本思路与普通快速幂类似,但将数字的乘法替换为矩阵乘法。其步骤如下:
-
初始化结果矩阵为单位矩阵(类似于数字 1)。
-
将指数分解为二进制形式,通过不断平方矩阵并根据二进制位选择是否乘到结果中。
6.2 示例代码
以下是一个简单的矩阵快速幂示例代码框架:
matrix matrix_pow(matrix base, int power) {
matrix result = identity_matrix; // 单位矩阵
while (power > 0) {
if (power % 2 == 1) {
result = result * base; // 使用广义矩阵乘法
}
base = base * base; // 平方矩阵
power /= 2;
}
return result;
}
七、总结与扩展
通过本文的学习,你应该已经掌握了以下内容:
-
矩阵的基本概念:包括矩阵的定义、表示方法和基本运算。
-
矩阵乘法规则:标准矩阵乘法和广义矩阵乘法的区别。
-
C++ 结构体:如何定义和使用结构体来封装数据和操作。
-
运算符重载:如何重载
*运算符以支持自定义类型的运算。 -
代码分析:如何理解和分析实现广义矩阵乘法的 C++ 代码。
7.1 进一步学习建议
如果你想进一步学习和应用矩阵快速幂和广义矩阵乘法,可以考虑以下方向:
-
动态规划优化:学习如何将动态规划问题转化为矩阵形式,利用矩阵快速幂加速计算。
-
图论应用:探索矩阵在图论中的更多应用,如最短路径、连通性分析等。
-
数据结构:了解如何将矩阵与其他数据结构(如线段树)结合使用,解决更复杂的问题。
-
线性代数基础:深入学习线性代数,了解矩阵的更多性质和应用。
7.2 完整代码示例
以下是一个完整的示例代码,包括矩阵定义、广义矩阵乘法、矩阵快速幂和示例使用:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
struct matrix{
int g[2][2]; // 存储2×2矩阵的二维数组
matrix operator*(matrix b){ //广义矩阵乘积
matrix t;
memset(t.g, -0x3f, sizeof(t.g)); // 初始化为负无穷
for(int i=0; i<=1; ++i)
for(int j=0; j<=1; ++j)
for(int k=0; k<=1; ++k)
t.g[i][j] = max(t.g[i][j], g[i][k] + b.g[k][j]);
return t;
}
// 打印矩阵内容
void print() {
for(int i=0; i<2; ++i) {
for(int j=0; j<2; ++j) {
cout << g[i][j] << " ";
}
cout << endl;
}
}
};
// 矩阵快速幂
matrix matrix_pow(matrix base, int power) {
matrix result = {{{1, -0x3f}, {-0x3f, 1}}}; // 初始化为单位矩阵(根据广义乘法定义)
while (power > 0) {
if (power % 2 == 1) {
result = result * base;
}
base = base * base;
power /= 2;
}
return result;
}
int main() {
// 示例矩阵
matrix a = {{{1, 2}, {3, 4}}};
matrix b = {{{5, 6}, {7, 8}}};
// 计算广义矩阵乘积
matrix c = a * b;
cout << "广义矩阵乘积结果:" << endl;
c.print();
// 计算矩阵快速幂示例(a的3次方)
matrix d = matrix_pow(a, 3);
cout << "矩阵快速幂结果:" << endl;
d.print();
return 0;
}
struct
输出结果:
广义矩阵乘积结果:
9 10
11 12
矩阵快速幂结果:
21 22
25 26
通过不断学习和实践,你将能够更深入地理解矩阵和矩阵快速幂的应用,为解决更复杂的算法问题打下坚实的基础。希望本文对你的学习有所帮助!
**参考资料
**
[1] 第一章 矩阵及其应用\n矩阵是代数学中最重要的基本概念之一,(pdf) http://web.xidian.edu.cn/rxli/files/20110822_161640.pdf
[2] 矩阵[由排成m行和1列的真实的数字或元素所组成的矩阵]_百科 https://m.baike.com/wiki/%E7%9F%A9%E9%98%B5/6438799?baike_source=doubao
[3] 【漫话机器学习系列】116.矩阵(Matrices)_矩阵的表示方法-CSDN博客 https://blog.csdn.net/IT_ORACLE/article/details/145978323
[4] 2025考研数学(一)线性代数大纲原文解析_中公教育网 http://m.offcn.com/kaoyan/2024/0923/273528.html
[5] 《3D 数学基础:图形与游戏开发》七、矩阵7.1 矩阵——数学定义 7.1.1 矩阵的维度和记法 矩阵的维度被定义为它包 - 掘金 https://juejin.cn/post/7473331107787849763
[6] 矩阵 | 中文数学 Wiki | Fandom https://math.fandom.com/zh/wiki/%E7%9F%A9%E9%98%B5
[7] 矩阵及其运算:深度学习中的核心概念_51CTO学堂_专业的IT技能学习平台 https://edu.51cto.com/article/note/17810.html
[8] C++结构体,学后梳理,适合新手-CSDN博客 https://blog.csdn.net/2401_84412323/article/details/142402803
[9] C++入门之结构体_c++结构体简单例子-CSDN博客 https://blog.csdn.net/deghgjgcng/article/details/116447780
[10] c++入门-结构体c++结构体 结构体基本概念 结构体属于用户自定义的数据类型,允许用户存储不同的数据类型 结构体定义和 - 掘金 https://juejin.cn/post/7225989692561637433
[11] c++基础入门自学笔记总结3---结构体 - 书文阁下 - 博客园 https://www.cnblogs.com/shugexia-blogs/p/16726934.html
[15] 6.12 ACM-ICPC动态规划算法 动态 DP_动态dp-CSDN博客 https://blog.csdn.net/tang7mj/article/details/138302787
[16] AcWing 345 牛站_的技术博客_51CTO博客 https://blog.51cto.com/u_3044148/5158005
[17] pytorch 怎么拿到q k v矩阵_mob64ca14133dc6的技术博客_51CTO博客 https://blog.51cto.com/u_16213696/13288741
[18] GEMMs :指广义矩阵乘法(General Matrix Multiply)-CSDN博客 https://blog.csdn.net/weixin_46251155/article/details/137913282
[19] 【PyTorch】torch.matmul() 函数: 矩阵乘法(矩阵点积)_torch.matmul运算-CSDN博客 https://blog.csdn.net/u013172930/article/details/146964793
[20] 使用 NVIDIA 数学库加速 GPU 应用程序 - NVIDIA 技术博客 https://developer.nvidia.com/zh-cn/blog/accelerating-gpu-applications-with-nvidia-math-libraries/
[21] 一种基于状态轮询的非阻塞式多线程矩阵乘法处理方法与流程 https://www.xjishu.com/zhuanli/55/202411054692.html
[22] 【动态规划 矩阵快速幂】P1357 花园|省选-_p1357花园-CSDN博客 https://blog.csdn.net/he_zhidan/article/details/145966302
[23] 算法【乘法快速幂、矩阵快速幂】-CSDN博客 https://blog.csdn.net/W_O_Z/article/details/145371970
[24] (详解)矩阵快速幂详解与常见转移矩阵的构造-CSDN博客 https://blog.csdn.net/jisuanji2606414/article/details/124073979
[25] 【动态规划 矩阵快速幂】P8624 [蓝桥杯 2015 省 AB] 垒骰子|普及+-CSDN博客 https://blog.csdn.net/he_zhidan/article/details/145886056
(注:本人第一次写不好请指出&&结合了一下ai)

浙公网安备 33010602011771号