知识网络1.3 矩阵乘法

以下是本节涉及的知识点

  • 矩阵乘法
  • 二维数组
  • 三重for循环以及常用的计数变量

本节跟前面两节相比,量不大,但是会比较难,因为矩阵乘法涉及到三重循环,难在我们是如何分析得到这三重循环以及这三重循环怎么写。同时还涉及到二维数组,如果稍有不注意很可能会晕。

我们还是从一个基本的情景开始:

(佟强作业题改)初始化两个二维矩阵A和B,其中A是一个M*N的矩阵,B是N*P的矩阵(其中M、N、P均为某个常数,我们假定M=3,N=4,P=2),矩阵里面的数字均为整数,计算矩阵C=AB,并输出矩阵C

佟强作业题原题会比现在这个版本简单,但是原题还涉及到数组指针和函数,在这里都省略了。

首先我们来补充一下基本的矩阵乘法的知识:
二维矩阵:一个数表,M*N的矩阵表示一个M行N列的数阵,其中有M*N个数。
矩阵乘法:两个矩阵的乘法为:当第一个矩阵的列数等于第二个矩阵的行数时才能进行。对于题目中的A B矩阵来说,刚好满足这个关系,则乘积为CC为一个M*P的矩阵。
C中的第i行第j列元素可以表示为:
c i j = ∑ k = 1 N a i k b k j c_{ij}=\sum_{k=1}^N a_{ik} b_{kj} cij=k=1Naikbkj
C中的第i行第j列元素A矩阵i行B矩阵j列的每个对应元素乘积之和。
比如:
C = A B = ( 1 2 3 4 5 6 ) ( 1 4 2 5 3 6 ) = ( 1 × 1 + 2 × 2 + 3 × 3 1 × 4 + 2 × 5 + 3 × 6 4 × 1 + 5 × 2 + 6 × 3 4 × 4 + 5 × 5 + 6 × 6 ) = ( 14 32 32 77 ) C=AB=\begin{pmatrix}1 & 2 & 3\\4 & 5 & 6\end{pmatrix}\begin{pmatrix}1 & 4 \\ 2 & 5 \\ 3 & 6 \end{pmatrix}=\begin{pmatrix}1×1+2×2+3×3 & 1×4+2×5+3×6 \\ 4×1+5×2+6×3 & 4×4+5×5+6×6\end{pmatrix}=\begin{pmatrix}14 & 32\\32 &77\end{pmatrix} C=AB=(142536)123456=(1×1+2×2+3×34×1+5×2+6×31×4+2×5+3×64×4+5×5+6×6)=(14323277)

文章目录

  • 矩阵乘法
    • 定义并初始化矩阵
    • 计算矩阵C第i行第j列元素的值
    • 计算矩阵C第i行所有元素的值
    • 计算矩阵C所有行的元素的值
    • 输出
    • 把临时变量提前定义
    • 小结

矩阵乘法

接下来我们要实现矩阵乘法。还是先把上述情景进行步骤分解:

  1. 定义并初始化存储矩阵的二维数组A B C
  2. 求出矩阵C中某一元素的值
  3. 对矩阵C中某行的每个元素求值
  4. 对矩阵C中的每行都进行上述操作
  5. 在屏幕上输出矩阵C

定义并初始化矩阵

首先要干的事情是定义矩阵。矩阵我们可以用二维数组来进行存储(虽然也可以用一维数组,但是二维显然更方便)。我们可以利用随机数初始化这个矩阵,也可以让用户输入一个矩阵,但这都是前两节细讲过的东西,在这里我们简单来就好,直接在代码里面对数组进行初始化。

#include
using namespace std;

int main(){
    const int M=3;
    const int N=4;
    const int P=2;
    
    int A[M][N]={
        1, 8, 5, 4,
        2, 6, 3, 8, 
        7, 2, 1, 9 
    };
    int B[N][P]={
        1, 0, 
        7, 4, 
        9, 3,
        1, 5
    };
    int C[M][P];
}

如上,我们还是先把常量MNP定义了,这样万一今后需要修改矩阵大小,从这里修改就可以了。AB我们使用数组初始化的方式直接初始化。为了让矩阵的形状更加清晰,我在这里把数字按矩阵本身的形状排列了。在C++里面,空格和缩进多数情况下不会影响程序运行,所以我们做到美观即可。矩阵内容是我随便输的。

计算矩阵C第i行第j列元素的值

矩阵乘法听起来很复杂,但也是有规律可循的。我们从一个最基本的情况做起:计算矩阵C第i行第j列元素的值。由前面的公式可知,矩阵C第i行第j列元素的值为,矩阵A第i行第1列元素与B的第1行第j列元素乘积,加上矩阵A第i行第2列元素与B的第2行第j列元素乘积,一直加到矩阵A第i行最后一列元素与B的最后一行第j列元素乘积。可以初步看出这是一个循环。
矩阵A第i行第1列元素与B的第1行第j列元素的乘积我们可以这么写:

A[i][1]*B[1][j] 

那么做到循环里面的时候,我们计算矩阵A第i行第k列元素与B的第k行第j列元素的乘积就这么写:

A[i][k]*B[k][j] 

这里面一共有N个这样的乘积,所以我们把这些乘积累加起来。这需要用到知识网络1.1里面介绍的求和的模式:

int sum=0;
for(int k=0;k<N;k++){
    sum+=A[i][k]*B[k][j];
}

求和之后,就很简单了,把这个和填到矩阵C第i行第j列元素里面即可:

C[i][j]=sum;

计算矩阵C第i行所有元素的值

我们现在会求一个元素的值了,那么求其余所有元素的值也是如法炮制。我们先试着把矩阵C第i行所有元素的值都求出来。也就是说此时前面提到的j就会从0一直到P-1进行循环。大概逻辑是这样的:

for(int j=0; j

把中间的文字替换成前面写出的代码,就有了如下的二重for循环:

for(int j=0; j<P; j++){
    int sum=0;
    for(int k=0;k<N;k++){
        sum+=A[i][k]*B[k][j];
    }
    C[i][j]=sum;
}

这段代码便能够为矩阵C的第i行整行求值了。

计算矩阵C所有行的元素的值

最后一步也是一样的了,我们既然能算一整行,那么只要对于矩阵C的每一行,都执行上述操作即可。大概逻辑是这样的:

for(int i=0; i

把文字替换为前面写出的代码,就有了如下怪物一样的三重for循环:

for(int i=0; i<M; i++){
    for(int j=0; j<P; j++){
        int sum=0;
        for(int k=0;k<N;k++){
            sum+=A[i][k]*B[k][j];
        }
        C[i][j]=sum;
    }
}

输出

最后一步是输出。由于是二维数组,所以我们也需要二重循环,逐行逐列对矩阵C进行输出。当然具体的输出格式按自己的喜好即可:

for(int i=0; i<M; i++){
    for(int j=0; j<P; j++){
        cout<<C[i][j]<<'\t';
    }
    cout<<endl;
}

把临时变量提前定义

当然到这里就可以结束了。但是我还想再提一点之前都没重视的地方:我们所有的临时变量(ijksum)都是在需要用的时候才被定义。但实际上,我们也可以在程序一开始的时候就把它们定义好。这样子后面写的时候,就不用再在for循环里面定义了,能省不少麻烦。
比如:

for(int i=0; i<M; i++){
    for(int j=0; j<P; j++){
        int sum=0;
        for(int k=0;k<N;k++){
            sum+=A[i][k]*B[k][j];
        }
        C[i][j]=sum;
    }
}

就可以替换为:

int i, j, k, sum;
for(i=0; i<M; i++){
    for(j=0; j<P; j++){
        sum=0;
        for(k=0;k<N;k++){
            sum+=A[i][k]*B[k][j];
        }
        C[i][j]=sum;
    }
}

小结

总结一下,我们现在总共写了些什么:

#include
using namespace std;

int main(){
    //定义常量 
    const int M=3;
    const int N=4;
    const int P=2;
    //定义矩阵并初始化 
    int A[M][N]={
        1, 8, 5, 4,
        2, 6, 3, 8, 
        7, 2, 1, 9 
    };
    int B[N][P]={
        1, 0, 
        7, 4, 
        9, 3,
        1, 5
    };
    int C[M][P];
    int i, j, k, sum;
    
    //对于矩阵C的每一行 
    for(i=0; i<M; i++){
        //对于矩阵C的第i行的每个元素 
        for(j=0; j<P; j++){
            //对于矩阵C的第i行第j列的元素进行求值 
            sum=0;
            //计算矩阵A第i行每个元素与矩阵B第j列每个元素的对应乘积之和 
            for(k=0;k<N;k++){
                sum+=A[i][k]*B[k][j];
            }
            //把这个乘积之和填到矩阵C的第i行第j列的元素里面 
            C[i][j]=sum;
        }
    }
    
    //对于矩阵C的每一行 
    for(i=0; i<M; i++){
        //对于矩阵C的第i行的每个元素
        for(j=0; j<P; j++){
            //输出矩阵C的第i行第j列的元素
            cout<<C[i][j]<<'\t';
        }
        cout<<endl;//当一行输出结束时换行 
    }
}

参见附件知识网络1.3.1,运行一下看看结果。

很幸运,本节没有更多的幺蛾子了,这一节就到这里!

你可能感兴趣的:(红助教程,Cpp,矩阵,二维数组,循环)