C++ 循环嵌套讲解
今天我来讲讲循环嵌套,这是一个十分重要的结构,大多数代码都需要用到循环嵌套。
而循环嵌套最重要的地方是对于它的理解,只要理解它是如何执行的,就可以轻松地打出关于它的代码。
循环嵌套
循环嵌套,并不是新的保留字,而是一种结构 ( 其实就是把多个循环扣在一起... ),循环嵌套是非常常用的,但是也是比较难以理解的。
一个循环嵌套的结构是这样的:
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
上一篇: C++ While及Do-while讲解与一本通平台讲解
下一篇: C++ 数组讲解