从频度引发的c语言多重for循环乃至编写算法思路的思考

7 篇文章 1 订阅
7 篇文章 0 订阅

首先需要声明的是,笔者是一名有C语言基础并正在为考研而复习数据结构的大学生,本篇文章中的for循环代码来自于清华大学严蔚敏教授出版的《数据结构》。

本篇博客适用于初学者理解C语言for循环,多重for循环、数据结构频度、线性代数矩阵等知识点。

整篇文章从频度开始,讲述两个矩阵相乘算法,最后讲述整个算法的设计原理

频度

for (i=1;i<=n;i++)    //频度为n+1
   for(j=1;j<n;j++)   //频度为n*(n+1)
   {
    c[i][j]=0;        //频度为n^2
    for(k=1;k<=n;k++) //频度为n^2*(n+1)
    c[i][j]=c[i][j]+a[i][k]*b[k][j]; //频度为n^3
    }
    

这是一段用于两个矩阵相乘的c代码

首先对频度(频度已在代码注释中)进行一下解释:
for (i=1;i<=n;i++) //频度为n+1
第一个for循环频度是n+1,因为在执行完第n次循环后,执行i++,开始了下一次即n+1次循环,因为n+1次循环碰壁了,什么意思?遇到了i<=n的这堵墙,条件不符合,所以循环结束。

所以实际有效执行次数是n次,但总共执行了n+1次。

for(j=1;j<n;j++) //频度为n*(n+1)
第二个for循环的频度是n*(n+1),这里有两个原因:
1.因为第一个for循环实际执行了n次,所以传递给第二个for循环n次。
2.类比第一个for循环,第二个for循环实际执行次数是n次,但最后一次碰壁了,所以总共执行了n+1次
3.总共就是n*(n+1)次

…别问我为什么不是n+(n+1)次,如果有这样疑问的同学需要重新学习一下c语言

c[i][j]=0; //频度为n^2
本段代码很容易理解了,从第一个for循环和第二个for循环得到的n*n次,因为第一个for循环有效传递了n次,第二个for循环也有效传递了n次

for(k=1;k<=n;k++) //频度为(n+1)n^2
第三个for循环分为两部分
1.从前两个for循环上得到了n*n次的循环,所以是n^2
2.类似第一个循环,总共执行了(n+1)次
所以一共循环了(n+1)n^2

c[i][j]=c[i][j]+a[i][k]*b[k][j]; //频度为n^3
从三个for循环上得到了n* n *n次循环,所以是n^3次


矩阵相乘过程

下面说明两个矩阵相乘的过程

两个矩阵相乘在线性代数是一个很基础的算法(或者叫算术)
在上述代码中是

c[i][j]=c[i][j]+a[i][k]*b[k][j]; 

其数学概念用一个例子可表示:
在这里插入图片描述

也就是说新矩阵中的11(第一行第一列,在后面的12或者21就是第一行第二列和第二行第一列)是由
第一个矩阵的第一行X第二个矩阵的第一列
看结果矩阵的字母即看得出,这里不多加叙述

假设第一个矩阵为A矩阵,第二个矩阵为B矩阵,第三个矩阵为C矩阵

下面结合代码和上面的图进行具体的算法分析
计算C矩阵的过程如下
①第一个for循环传递i=1,i<=2,为什么小于2?后面有解释
②第二个for循环传递j=1,j<=2
c[1][1]=0
④第三个for循环传递k=1,K<=2
c[1][1]=c[1][1]+a[1][1]*b[1][1]
⑥第三个for循环传递k=2
c[1][1]=c[1][1]+a[1][2]*b[2][1] //这里的右值c[1][1]是第5个步骤里的结果
在这里插入图片描述
至此,C矩阵中C11已计算出来,现在进入到计算C12
①第一个for循环还是1
②第二个for循环传递j=2
c[1][2]=0
④第三个for循环传递k=1
c[1][2]=c[1][2]+a[1][1]*b[1][2] //注意,b的第二个元素从1变成了2
⑥第三个for循环传递k=2
c[1][2]=c[1][2]+a[1][2]*b[2][2] //这里的右值c[1][2]是第5个步骤里的结果
在这里插入图片描述
当C矩阵中第一行的两个元素计算完后,开始计算C矩阵中的第二行元素,即C21和C22

至此,第一个for循环开始进入i=2时代

我相信现在读者应该对 i 和 j 为什么小于等于2有一定的想法

因为C矩阵的行为2,列为2
c[i][j]最大就是c[2][2]

所以当C矩阵的第一行的两个元素都得出结果后,c[1][?]就变成了c[2][?]

对for循环,大家也应该有个理解了,可以直接看下一段话
第一个for循环传递i=1给第二个for循环
第二个for循环传递j=1给第三个for循环
第三个for循环传递了k=1之后,代码执行到k=2,并执行完后,再返回到第二个for循环
然后
第二个for循环传递j=2给第三个for循环
第三个for循环传递了k=1之后,代码执行到k=2,并执行完后,再返回到第二个for循环
然后 j 到顶了,再返回到第一个for循环,i 就变成了2,再进行一次上面的循环

通俗的来说,里面的for循环循环结束后,才会回到表面的for循环


思考算法的设计原理

下面,我们来思考一下整个算法是怎么由内而外进行设计的

第一个问题,我们看到这段代码,映入眼帘的就是三个for循环(以后你可能会遇到有四五个甚至更多的for循环)那么,这三个for循环是干嘛的?

由第三段代码

c[i][j]=0;

可知,第一个for循环提供的 i 就是C矩阵的行数,第二个for循环提供的 j 就是C矩阵的列数

由第五段代码

c[i][j]=c[i][j]+a[i][k]*b[k][j];

可知,第三个for循环提供的 k 是A矩阵的列数,B矩阵的行数

第二个问题,三个for循环这样安排有什么意义?
很明显,当计算C矩阵第一个元素的时候,即C11,需要 i 和 j 都为1,所以第一个for循环传递 i = 1 ,第二个for循环传递 j = 1。从更深层次来说,是因为C11是先有A矩阵的第1行开始,乘B矩阵的第1列,注意,是第1行,这个“行”字,所以把C的行数的循环放在最上面,可以理解为行最大吧
第二个for循环就是C矩阵的列了,除了行就是列,这个不难理解
重点是第三个for循环,很巧妙的变化了A矩阵的列数和B矩阵的行数,也是我认为这段代码中最具有艺术性的循环

我们知道,要想用代码实现一个程序或者项目,首先要设计的它的数学模型

整段代码想要实现的是两个矩阵相乘,两个矩阵相乘的概念我们在上面已经描述了,所以我们可以知道C11=A11XB11+A12XB21

从代码可以看到变化的是A的第二个元素和B的第一个元素,并且

A的第二个元素=B的第一个元素=K

所以我们可以设置一个K,并且K<=2


一个苹果是由苹果核生长出来的


进行算法设计

怎么去设计这个算法?

我们知道,是通过A矩阵和B矩阵计算C矩阵,三个矩阵的行列数都是2
并且我们从概念知道C11=A11XB11+A12XB21
所以我们需要进行C11=A11XB11C11=A12XB21
通过研究
我们发现:A的第二个元素=B的第一个元素=K
所以我们可以设计一段代码
即c[i][j]=a[i][]+b[][j]
并且设置一个K
使代码变成

c[i][j]=a[i][k]+b[k][j]

从C11=A11XB11C11=A12XB21
可以得知要进行两次K的变换
所以设计一个for循环

for(K=1;K<=2;K++)

C矩阵一开始是0,所以设计

c[i][j]=0

我们至此已经设计完成了计算单个元素的算法

所以我们需要设计一段代码去实现C矩阵的四个元素
C的四个元素是C11,C12,C21,C22
所以我们分别设计两个for循环
去进行 i 和 j 的变换
又因为计算是先从行开始的,所以这段代码即为

for(i=1;i<=2;i++)
  for(j=1;j<=2;j++)

至此,代码设计完成。

2021年6月28日 00:06:21

希望本篇博客可以对对计算机感兴趣或者正在进行计算机学习的初学者有启发作用!

谢谢大家的赏眼!

  • 23
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 10
    评论
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端小王hs

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值