• 微信号
  • 微信号
您当前的位置:首页 > 学海无涯 > 茑语花香>C++ 循环嵌套讲解

C++ 循环嵌套讲解

孤峰 孤峰家 2023-09-21 204人阅读

今天我来讲讲循环嵌套,这是一个十分重要的结构,大多数代码都需要用到循环嵌套。

而循环嵌套最重要的地方是对于它的理解,只要理解它是如何执行的,就可以轻松地打出关于它的代码。

循环嵌套

循环嵌套,并不是新的保留字,而是一种结构 ( 其实就是把多个循环扣在一起... ),循环嵌套是非常常用的,但是也是比较难以理解的。

一个循环嵌套的结构是这样的:

for(i=1;i<=n;i++)

{

for(j=1;j<=n;j++)//在循环嵌套中,不同的循环中的增量变量要不同

{

cout<<i<<' '<<j<<endl;//切记不要打错了增量变量,否则会出现奇怪的现象

}

}

//当然不同的循环也是可以的

i=n;

while(i!=0)

{

for(j=1;j<=n;j++)

{

cout<<i<<' '<<j<<endl;

}

i--;

}

//或者是这样

do

{

for(j=1;j<=n;j++)

{

cout<<i<<' '<<j<<endl;

}

i--;

}while(i!=0);

//又或者是这样的

for(i=1;i<=n;i++)

{

while(i!=1)

{

cout<<i<<endl;

}

}

//当然可以是多重嵌套

for(i=1;i<=n;i++)

{

for(j=1;j<=m;j++)

{

for(k=1;k<=l;k++)

{

cout<<i<<' '<<j<<' '<<k<<endl;

}

}

}

//甚至是更多的循环

while(true)

{

while(true)

{

while(true)

{

while(true)

{

while(true)

{

...

}

}

}

}

}

//显然这么做很少见...

那么,这样可以解决什么问题呢?

例如要输入一个矩形,就要利用循环嵌套进行输入 ; 或者是枚举一些含有多个未知数的方程,例如百钱买百鸡问题 ; 又或者是完成质因数分解...这些都要利用循环嵌套来完成。

而循环嵌套是怎么执行的呢?

进入第一层循环,执行其内部的语句( 包括新的循环 )。

进入新一层的循环,并执行其内部的语句( 也包括新的循环 )。

当没有新的循环出现时,就会反复执行自己内部的代码,直到自己内部的代码执行完毕后退出这一层代码。

退出后,来到第一层循环处,重新执行内部的代码。

这一个过程总共执行了 第一层循环次数 * 第二层循环次数 * 第三层循环次数 ( 如果存在 ) *第四层循环次数 ( 如果存在 ) ...

这两个是保留字,是可以作用于循环内的。

break 的意义是打破,用于 跳出本层循环 ,不再执行这个循环内的代码,跳出后执行上一层的循环中的代码

continue 的意义是继续,用于重新回到本层循环的头部 ( 也就是控制循环执行的地方,并且会像结束了一次循环那样进行判断是否继续执行 )。要注意的是 continue 的实际操作是提前执行下一次的循环,也就是说,如果本次是较后一次循环,那么在使用 continue 后就会退出循环。

这两个保留字在循环内的所产生的作用是十分大的,你一定可以在合适的地方用到他们。

例如我想累加一堆数字,在这些数字的和满足 100 时就退出循环,并执行后面的代码,那么久可以这样写:

...

int n,sum=0;

while(true)

{

cin>>n;//输入每次累加的数

sum+=n;//累加

if(sum>=100) break;//查看是否满足 sum 大于 100,是则退出循环

}

...

又或者我想输入一个数,并且按照一定的程序处理它,但是如果输入的数字不能为 0,如果输入的数是 0,就要重新输入,那么就可以这样写:

...

int n;

while(true)

{

cin>>n;//输入要处理的数

if(n==0) continue;//如果输入的数为 0 ,就重新回到while

...//复杂但是可以由三个点概括的处理

cout<<n<<endl;//处理完成后输出

}

通过这样详细的讲解,相信你已经对循环嵌套,break 和 continue 有了一定的了解。

2026 - 2033,1091 - 1101

你不会以为没有这个东西吧?标题没写,但是正文还是写了的。

下文将会使用两个词 : 第N层循环第N次循环,这两个的意义是不同的 : 一个是指循环的层数 ( 也就是循环的嵌套 ) ; 第二个是指某一层的循环的某一次循环 ( 也就是在一个循环中循环的次数 )。一定要分清楚两者,否则是没有办法理解的。

2026:【例4.12】阶乘和

一道一看就知道用循环嵌套的题目,一定要用 long long,否则会溢出。

#include<iostream>

using namespace std;

int **in()

{

long long ans=0,sum=1;//用long long

int i,j,n;

cin>>n;

for(i=1;i<=n;i++)

{

sum=1;//累乘的数初始化一定要是1

for(j=1;j<=i;j++) sum*=j;//累乘 sum

ans+=sum;//累加至 ans 当中

}

cout<<ans<<endl;//输出 ans 的值

return 0;

}

理解了循环嵌套执行的方法后,就可以十分容易的通过这个题目了。

2027:【例4.13】三角形

这道题是输出一个平面图形,输出的时候是从上到下,从左到右的。

所以,我们在第一层第一次循环是输出第一行,第一层第二次循环是输出第二行...以此类推。然后,在每一次的循环中,我们在套入一个新的循环,来输出一行内的字符 ' * ' 的个数。在每一行中,将会输出 层数 个字符 ' * ',所以内层的循环次数就是外层的循环的变量 i 。

通过这两个循环的控制,就可以输出字符直角三角形了,代码如下:

#include<iostream>

using namespace std;

int **in()

{

int i,j,n;

cin>>n;//输出 n 层的直角三角形

for(i=1;i<=n;i++)//第一层循环(控制每一行)

{

for(j=1;j<=i;j++) cout<<'*';//第二层循环(控制一行中的字符'*'的个数,i个)

cout<<endl;//在每输出完一行之后进行一次换行

}

return 0;

}

这道题在明白了循环嵌套的执行过程后就可以做出来。

2028:【例4.14】百钱买百鸡

百钱买百鸡问题,这道题的方法在于用循环去枚举每一种鸡的数量,找到所有符合条件的组合方式。这就要用到三重循环了,每一层都枚举一种鸡的数量,到最内层后判断枚举的三种鸡的数量是否满足条件,如果满足条件就输出。

代码如下:

#include<iostream>

using namespace std;

int **in()

{

int i,j,k;

for(i=0;i<=20;i++)//第一层循环,枚举公鸡的数量(最多20只公鸡)

{

for(j=0;j<=33;j++)//第二层循环,枚举母鸡的数量(最多33只母鸡)

{

for(k=0;k<=300;k+=3)//第三层循环,枚举鸡雏的数量(最多300只鸡雏)

{

if(i+j+k==100&&i*5+j*3+k/3==100)//判断三种鸡是否满足条件

{

cout<<i<<' '<<j<<' '<<k<<endl;//满足条件就输出结果

}

}

}

}

return 0;

}//压行的老毛病又犯了...好想压行...(但是为了方便大家看懂就不压行了)

这题十分简单,通过枚举鸡即可。

2029:【例4.15】水仙花数

ABC=A(3次方)+B(3次方)+C(3次方)可转化为2*2=4

这道题同样是利用枚举,枚举三个数位上的数 ( 0 ~ 9,较高位不能为 0 ) 。

代码如下:

#include<iostream>

using namespace std;

int **in()

{

int i,j,k;

for(i=1;i<=9;i++)//枚举第一位数(从 1 到 9 ,首位不能为 0 , 所以不包含 0 )

{

for(j=0;j<=9;j++)//枚举第二位数(从 0 到 9 )

{

for(k=0;k<=9;k++)//枚举第三位数(从 0 到 9 )

{

if(i*100+j*10+k==i*i*i+j*j*j+k*k*k)//判断是否成立

{

cout<<i<<j<<k<<endl;//将三位数紧贴在一起输出就可以判定为三位数

}

}

}

}

return 0;

}//可恶的压行的毛病...

与上一题类似,都是枚举+判断+输出。

2030:【例4.16】找素数

在之后的学习中是不是就会用到素数,学会找到它们是十分重要的。( 素数 = 质数 )

找到素数首先要知道素数的概念是什么,一个大于 1 的数,除了 1 和它本身,不能被其它自然数整除的整数叫做素数

通过这个概念,我们就可以找出素数了。首先枚举从 a 到 b 的所有数,判断它是否为素数,是则输出。

代码如下:

#include<iostream>

#include<c**th>

using namespace std;

int **in()

{

int i,j,a,b,f;

cin>>a>>b;

for(i=a;i<=b;i++)

{

f=1;//假设它是一个素数

for(j=2;j<=i/2;j++)//j 到 i/2 是优化,如果 j 大于 i/2 的话就不可能整除

{

if(i%j==0)

{

f=0;//如果可以整除了就说明它不是素数

break;//不是质数直接退出

}

}

if(f==1) cout<<i<<endl;//当它是素数时就输出

}

return 0;

}

整个代码分为枚举 a 至 b 和判断是否为素数两部分组成,理解好了就可以打出来。

2031:【例4.17】四位完全平方数

看了题目后第一反应应该是枚举四位数,然后判断是否满足前两位相等,后两位相等且是完全平方数。

但是还有更加简单的方法,就是枚举平方根的根,开方后是四位数的根是从 40 开始到 98 的,因此,我们就只需要枚举 59 次了,大大减少了枚举次数,增加了效率。

代码如下:

#include<iostream>

using namespace std;

int **in()

{

int i,x,a,b,c,d;

for(i=40;i<=98;i++)//枚举根

{

x=i*i;//求出开方后的结果

a=x/1000;//求第1位

b=x/百%10;//求第2位

c=x/10%10;//求第3位

d=x%10;//求第4位

if(a==b&&c==d&&x>999&&x<=9999) cout<<x<<endl;//满足条件输出结果

}

return 0;

}

换另一种角度解决问题也许可以大大增加代码执行的效率。

2032:【例4.18】分解质因数

这道题的难点在于枚举因数的顺序很难控制,还要找出质数,但是我们可以枚举从小到大的质数,然后不断的将这个数分解。

那么可能会有人觉得顺序都不正确,但是乘数可以随意调换位置且乘积不变。

又可能会有人觉得下面的代码它并没有找质数,只是单纯的在累加,那要仔细思考一下,如果这个数可以被 2 的倍数整除,那么它同样也可以被 2 整除,当这个数多次被 2 除之后就等同于被 2 的倍数除了。因此在枚举到合数时,它就早已不能整除了,要是能整除,早就被它的多个质数的乘积整除了。

例如 60,它可以被 2 整除并且它可以被 2 除 2 次,然后就变为了 15,这时,2 不能整除 15 了,只好增加 1,2 变为 3,15 又被整除为 5 了。这时,到了 4,虽然 60 可以乘除 4,但是它可以被两个 2 代替,因为 2*2=4。

代码如下:

#include<iostream>

using namespace std;

int **in()

{

int i=2,n;//除数定为**小的质数 2

cin>>n;

cout<<n<<'=';

while(n!=1)//读入的数在变为 1 之前都要一直循环下去

{

while(n%i==0)//满足整除的条件

{

cout<<i;//输出这个除数

n/=i;//将它除以这个除数

if(n!=1) cout<<'*';//输出字符'*'

}

i++;//每次增加

}

return 0;

}

明白了解题的思路后就一定能够做出来的。

2033:【例4.19】阶乘之和

这道题就是 2026 的升级版,但是这道题相比于 2026 就要难上许多了。

如果利用每一次求出这个数的阶乘,然后取后 6 位再加入到总和当中,这样一定就会超出时间限制(简称TLE),因为一个程序在测评机上测评时,需要在一定的时间内完成题目的所有要求 ( 时间的限制一般是 1s ),如果没有在规定的时间内完成题目的要求,就会被判定为超时。要知道时间复杂度的概念,是指一个程序执行所需要循环的次数,表示方法为 O(Time) 的形式,其中的 Time 为循环次数,例如计算 10 个数字的积,时间复杂度就是 O(10),如果计算从 1 到 10 的数的阶乘和的时间复杂度就是 O(55)。

这道题如果使用计算再加的方法就要进行非常多次循环,为了防止超时,我们需要改进代码。但是,思考一下,x! 是否等于 ( x - 1 )! · x 呢?那么求出了 ( x - 1 )! 就只需要乘以 x 即可,那么我们只需要依次乘以 x 就可以得出阶乘的结果。

代码如下:

#include<iostream>

using namespace std;

int **in()

{

int i,n,a=1,b=0;

cin>>n;

for(i=1;i<=n;i++)

{

a*=i;//每次乘以i,求出新的阶乘的结果

a%=1000000;//取后六位

b+=a;//累加后六位

}

cout<<b%1000000<<endl;//输出累加

return 0;

}

这题需要把 x! 拆解,只要完成了这一步的思想,就可以容易的解决这一道题了。

1091:求阶乘的和

这一道题...比 2026 还要简单 ( 甚至不需要用 long long ),直接贴代码了。

代码如下:

#include<iostream>

using namespace std;

int **in()

{

int i,j,n,x=1,sum=0;

cin>>n;

for(i=1;i<=n;i++)

{

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

{

x=x*j;

}

sum=sum+x;

x=1;

}

cout<<sum<<endl;

return 0;

}

会做 2026 就绝对会做这一道题...

1092:求出e的值

这道题可以说是 2033 的变式,它们都可以利用分解 x! 的思想。

只需用 1 除以求出来的阶乘即可,代码如下:

#include<iostream>

#include<cstdio>

using namespace std;

int **in()

{

int n,i;

double e=1;

long long sum=1;

cin>>n;

for(i=1;i<=n;i++)

{

sum=sum*i;//分解x!的思想进行求值

e=e+1.0/sum;//累加e的值

}

printf("%.10lf\n",e);//保留后10位较好使用printf

return 0;

}

1093:计算多项式的值

这道题很简单,求出每次的结果并累加即可。

代码如下:

#include<iostream>

#include<cstdio>

#include<c**th>

using namespace std;

int **in()

{

int n;

double sum=0,x;

cin>>x>>n;

for(n;n>=1;n--)

{

sum=sum+pow(x,n);//利用 c**th 库的 pow 函数可以方便的求出开方值

}

printf("%.2lf",sum*1.0+1);

return 0;

}

pow 函数 下方的例子均为 pow ( N , M )

pow 函数是 c**th 库当中的,进行求开方值的函数,它会返回 N的M次方 的值 ( 可以将它的返回值当做一个数字进行使用 )

1094:与7无关的数

根据题意求即可,将与 7 无关的数全部进行平方计算加入总和中即可。

代码如下:

#include<iostream>

#include<c**th>

using namespace std;

int **in()

{

int i,n,g,s,b,sum=0;

cin>>n;

for(i=1;i<=n;i++)

{

if(i%7!=0)//是否满足不是7的倍数

{

g=i%10;//分离个位

s=i/10%10;//分离十位

if(g!=7&&s!=7)//判断十位和个位都不为7

{

sum=sum+pow(i,2);//与7无关,计算平方并加入总和中

}

}

}

cout<<sum<<endl;//输出总和

return 0;

}

1095:数1的个数

这道题,本来是想第一层循环进行枚举数字,第二层循环进行分离各个数位,但是这个数位的数量太少了,完全可以不使用循环进行分离,所以它就变得简单了吧?

#include<iostream>

using namespace std;

int **in()

{

int i,n,sum=0,g,s,b,q,w;

cin>>n;

for(i=1;i<=n;i++)

{

g=i/1%10;

s=i/10%10;

b=i/百%10;

q=i/1000%10;

w=1/10000%10;//分离各个数位

if(g==1)//个位是否为1

{

sum++;

}

if(s==1)//十位是否为1

{

sum++;

}

if(b==1)//百位是否为1

{

sum++;

}

if(q==1)//千位是否为1

{

sum++;

}

if(w==1)//万位是否为1

{

sum++;

}

}

cout<<sum<<endl;

return 0;

}

1096:数字统计

这道题就是对上一题做了一个升级,但是并没有太难,思想都是类似的。

代码如下:

#include<iostream>

using namespace std;

int **in()

{

int i,j,L,R,sum=0;

cin>>L>>R;

for(i=L;i<=R;i++)//枚举数位

{

for(j=i;j>0;j/=10)

{

if(j%10==2)

sum++;

}

}

cout<<sum<<endl;

return 0;

}

类似上一题。

1097:画矩形

这道题画的矩形有两种类型,一种是实心的,一种是空心的。实心的很简单,空心的就需要思考。

空心的矩形需要在第一行,较后一行,第一列,较后一列输出,其余的地方就输出空格。那么这样就好办了,当 i = 1 或 i = 高度 或 j = 1 或 j = 宽度 时就要输出。

代码如下:

#include<iostream>

#include<cstdio>

#include<c**th>

using namespace std;

int **in()

{

int j,i,n,t,x,y;

char a;

cin>>x>>y>>a>>t;

if(t==1)

{

for(i=1;i<=x;i++)

{

for(j=1;j<=y;j++)

{

cout<<a;//实心的矩形

}

cout<<endl;

}

}

if(t==0)

{

for(i=1;i<=x;i++)

{

for(j=1;j<=y;j++)

{

if(i==1||i==x||j==1||j==y)//输出的条件

{

cout<<a;

}

else

cout<<' ';//否则就输出空格

}

cout<<endl;

}

}

return 0;

}

这道题重要的是理解空心的矩形要怎么画就可以做对了。

1098:质因数分解

这道题只需枚举 n 的小的质数,再用 n 除即可。

代码如下:

#include<iostream>

#include<c**th>

using namespace std;

int **in()

{

int i,j,n;

cin>>n;

for(i=2;i<=n/2;i++)//优化

{

if(n%i==0)//判断是否可以除尽

{

cout<<n/i<<endl;//满足就输出

return 0;

}

}

}

从小分解,十分简单。

1099:第n小的质数

从小往大找到第 n 个质数即可。

代码如下:

#include<iostream>

using namespace std;

int **in()

{

int n;

int i,j;

int sum=0;

cin>>n;

for(i=2; ;i++)

{

for(j=2;j<=i/2&&i%j!=0;j++);

if(j>i/2)

{

sum++;

if(sum==n)

{

cout<<i<<endl;

return 0;

}

}

}

return 0;

}

重点在于找到质数。

1100:金币

这道题是一道模拟题,就是同过模拟整一个的执行过程,记录执行成果。

代码如下:

#include<iostream>

using namespace std;

int **in()

{

int n,d=0,j,i,sum=0;

cin>>n;

for(i=1; ;i++)

{

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

{

sum=sum+i;

d++;

if(d==n)

{

cout<<sum<<endl;

return 0;

}

}

}

return 0;

}

模拟就是直接模拟...

1101:不定方程求解

这一题有 2 个未知数,我们使用枚举的方法进行求解即可,即类似于百钱买百鸡。

代码如下:

#include<iostream>

using namespace std;

int **in()

{

int x,y,a,c,b,sum=0;

cin>>a>>b>>c;

for(x=0;x<=c/a;x++)//枚举x的值

{

for(y=0;y<=c/b;y++)//枚举y的值

{

if(a*x+b*y==c)//求解

{

sum++;//满足组数加1

}

}

}

cout<<sum<<endl;//输出最终组数

return 0;

}

这题要枚举两个未知数,并判断方程是否成立,比较简单。

好了,题目都讲完了。

转载:感谢您阅览,转载请注明文章出处“来源从小爱孤峰知识网:一个分享知识和生活随笔记录的知识小站”。

链接:C++ 循环嵌套讲解http://www.gufeng7.com/niaolang/1848.html

联系:如果侵犯了你的权益请来信告知我们删除。邮箱:119882116@qq.com