现实生活中,我们要处理的问题往往有很多规律性的重复操作,例如要找出上百万整数的最值,或者计算某次考试全班每位同学的平均分。这个时候仅仅使用前面的顺序结构和选择结构,对于重复性的每一步操作都写出对应的语句是不现实的,可以使用循环语句让计算机反复执行完全相同或者相似的任务。学习了循环结构,我们更能体会到计算机程序的威力!
一、循环结构
我们先来看一个简单的问题,输出5行Hello World
,这里当然可以使用顺序结构实现:
#include<iostream> using namespace std; int main() { cout<<"Hello World"<<endl; cout<<"Hello World"<<endl; cout<<"Hello World"<<endl; cout<<"Hello World"<<endl; cout<<"Hello World"<<endl; return 0; }
扩大问题规模,输出100行(或者成千上万行)Hello World
,很显然,这个时候书写100行(甚至更多)cout<<"Hello World"<<endl;
是不可取的。我们编写程序是要让使用程序的人偷懒,当然不能让编写程序的人累死!
再改变一下需求,首先输入一个正整数n,然后输出n行Hello World
。这个时候即使想用上面的笨办法也无法解决了。
像上面的要重复执行完全相同的任务,使用顺序结构解决问题是不可取的,甚至也是无法完成的。这个时候需要使用程序三大结构的循环结构来解决,而循环结构不仅仅可以重复执行完全相同的任务,也能重复执行相似的任务。
我们先来看使用循环结构处理上述问题的流程图:


可以看出,判断条件成立的话,会执行输出Hello World
和i++(这样被重复执行的部分称为循环体),然后又回去判断条件是否成立...直到某次回去判断发现条件不成立就退出循环不再执行循环体了。简单地说,就是当条件成立的时候,一直执行循环体。
循环结构的流程图和选择结构相似,都出现了条件的判断,不同的是,循环结构有一个返回到条件判断前的流程箭头。正是这个流程实现了循环结构当条件成立的时候,一直执行循环体的特殊功能。
从流程图中可以看出,变量i对循环结构很重要,不仅仅是循环的条件是用i来描述的,并且在进入循环判断前i有初值,在循环体中还有一条语句在改变i的值(这条语句也很重要,正是因为控制变量i的值在变化所以才能在某次执行完循环体后判断条件成立了退出循环)。这里的变量i称为循环的控制变量,正是它决定了循环的执行流程。我们可以通过追踪i值的变化情况来分析循环的执行流程:

判断前 i的值 | i<=5 是否成立 | 执行循环体 | 执行循环体后 i的值 |
1 | Y | 输出Hello World ;i++; | 2 |
2 | Y | 输出Hello World ;i++; | 3 |
3 | Y | 输出Hello World ;i++; | 4 |
4 | Y | 输出Hello World ;i++; | 5 |
5 | Y | 输出Hello World ;i++; | 6 |
6 | N | 退出循环 |
上面介绍的通过追踪循环控制变量值变化情况来分析循环结构执行流程的方法对于初学者来说比较重要,有了这个强有力的工具,我们能够全面把握循环结构执行流程的细节。我们后面阅读循环结构代码感觉困难的时候,可以用这样的方法去追踪控制变量分析循环执行流程,往往追踪几次重复操作就能理解循环的意图。
二、while循环
C++中常用的循环语句有for循环、while循环和do...while循环。这里先介绍while循环,原因是while循环和循环结构的流程图一致,从流程图可以毫无压力地写出while循环:

#include<iostream> using namespace std; int main() { int i; i = 1; while(i<=5){ cout<<"Hello World"<<endl; i++; } return 0; }

#include<iostream> using namespace std; int main() { int i,n; cin>>n; i = 1; while(i<=n){ cout<<"Hello World"<<endl; i++; } return 0; }
从上面的例子可以总结出while循环语句的用法如下:
while(条件){ 循环体; }
条件的描述和循环的控制变量有关,那么在while循环前得有循环控制变量的初始化语句;在循环体中,还得有语句改变控制变量的值,这样某次循环体执行后再判断循环条件时由于控制变量值改变导致条件不成立而退出循环。

对应左侧流程图,更详细while循环的一般使用方法如下:
控制变量初始化语句; while(用控制变量描述的循环条件){ 要重复执行的语句; 改变控制变量的值的语句; }
将关键字while读作“当”,那么while循环和自然语言很接近,就是当条件成立时,一直执行循环体的内容。
对于可以用循环结构解决的问题,有时候循环的次数很明显,就像上面的两个例子,有时候循环的次数不明显而循环的条件很明显,我们来看下面的例子:

分析:a是木棍的长度,循环的条件可以描述为a>1,循环体中使用a / = 2;
来记录木棍每次取半后的长度,使用计数器来记录取半的次数,其实就是循环执行的次数。本例循环条件很明显,循环次数不明确,其实求解的正是循环执行次数。
#include<iostream> using namespace std; int main() { int a,days = 1; cin>>a; while(a>1){ days ++; a /= 2; } cout<<days; return 0; }
三、可控的循环与无限循环
竞赛时,我们是要通过有限的步骤在有限的时间(一般是1s内)得出问题的答案,所以用到循环结构来实现重复相似计算时,肯定最后要退出循环(甚至为了提高效率需要想尽办法减少循环次数),这样的循环就是可控的循环。
但是初学者可能不小心就写出不可控的无限循环,也称为“死循环”,这样的程序提交后肯定会超时(TLE)。例如不小心将判断相等写成了赋值:
int n; cin>>n; while(n=1){ //n==1不小心写成n=1,造成“死循环” }
“死循环”在竞赛时不会用到,但是在一些特殊的场合会用到,例如程序控制的自动饮水机,一旦发现需要烧水的时候就开始加热烧水,烧开后停止加热,这里编程时就需要使用死循环,这样只要接通了电源,饮水机就会永不停止地执行任务。