循环结构

一、while语句

“长亭外,古道边...” -- 《送别》

国学大师告诉大家,当我们还不会背书的时候,就一直读啊,读啊,读啊,读着读着就会背了。

1、背书循环

while(不会背)
{
   背书;
}
看电视
循环轮次 会背了吗? 背书
1 不会(一开始) 长亭外,古道边...
2 不会
3 长亭外,古道边....
4 长亭外,古道边...
... ......
n 会了 退出背书的循环,看电视去

2、while语句要素

初始状态;
  while(表达式) 
  {
    语句; 
    状态变化;
  }
  后续语句;

例如: 大师告诉小明,背书10遍就可以看电视了。

int i = 0;
  while (i < 10)
  {
    cout << "长亭外,古道边" << endl;
    i++;
  }
  cout << "终于可以看电视了" << endl;

3、要素的理解

  • 退出条件:背10遍,那么i == 10就退出(从0开始)
  • 循环条件:i < 10
  • 进入:i = 0时,表达式为true
  • 循环:i++ 并且小于10时,表达式为true
  • 退出:i ++ 为10时,表达式为false
  • 状态:
    • 初始:i = 0
    • 变化:i++
    • 退出:i == 10
  • 执行语句:用来放置在循环里执行的业务,例如输出啊,运算啊之类。

二、死循环

1、死循环

如果表达式永远是true,则while就会一直在里面循环,这种情况称之为死循环。

2、死循环的形式-主动死循环

主动死循环指特意写成死循环结构,为了某种场景应用。

例如死循环接受键盘输入,输入q退出,其它字符作为指令进行处理。

char c;
  while (true) //死循环
  {
    cout << "输入一个字符,q表示退出:";
    cin >> c;
    if (c == 'q')
      break;
    cout << "你输入的是:" << c << endl;
  }

3、bug死循环

bug死循环指由于代码写的不好,导致循环退不出。

这种情况的危害很大,严重的甚至会导致计算机资源耗光死机,在编写循环结构的时候要特别注意。

例如以下代码:

int i = 1;
  while (i != 10)
  {
     语句;
     i += 2; // i = i + 2;
  }

4、break跳出循环

循环的退出,一种方法是表达式变成false,另一种方法是显示的调用break语句。

当在循环里执行break语句时,立即跳出循环(不会执行break后面的语句)。

while(true)
  {
    语句1;
    break;
    语句2;//这句执行不到了
  }

5、break的if表达式与while表达式的关系

一般循环有两种形态:while(表达式)与while(true)+break:

  • while(表达式)
    while(i <= 10)
    {
      ......
    }
    
  • while(true) + break
    while(true)
    {
      .....
      if (i > 10) break;
    }
    
  • if的表达式,一般为while表达式的取反,(或边界条件 )。

三、for语句

在while里,我们学到了循环结构的知识:

  1. 表达式:
    • 初始值:初始状态使得表达式初始值为真,从而进入循环。
    • 中间值:状态变化,表达式的值继续为真,保持循环。
    • 结束值:状态变化,表达式值变成假,退出循环。
  2. 状态变量:
    • 初始值:状态开始的值,使得表达式为真,进入循环。
    • 状态变化:在每次循环时变化状态,到某个状态值时,表达式变成假,退出循环。
  3. 执行语句
    • 语句体,在循环里面执行具体的业务。

在很多案例里,表达式和状态都是类似的,例如:

表达式:i < 1000
状态变化:i++

真正变化的都是执行语句,如在循环里执行输出、累加等等。

for语句结构将初始状态、表达式、状态变化都提炼到了语句结构里,语句体里只保留了执行语句。

for(int i=0; i< 10; i++) //for结构
  cout << i << endl; //执行语句

1、for语句

//for里面的三个部分,中间用分号;隔开
//for(初始状态; 表达式; 状态变化)
for(i=0; i<10; i++)
{
  //执行语句
  cout << i << endl;
}

for语句把控制部分(初始状态、表达式、状态变化)提炼到了一起,使结构更加清晰,但背后逻辑与while结构是一样的:

  • 第一步,设初始状态:i = 0。
  • 第二步,判断表达式,为真进入循环,否则退出:i < 10。
  • 第三步,执行语句(循环体里的语句):cout << i << endl;
  • 第四步,状态变化:i++
  • 第五步,继续判断表达式,为真继续循环,否则退出: i < 10。

图解

轮次 状态 表达式结果 执行语句
1 0 true cout << 0 << endl;
2 1 cout << 1 << endl;
3 2 cout << 2 << endl;
4 3 cout << 3 << endl;
5 4 cout << 4 << endl;
6 5 cout << 5 << endl;
7 6 cout << 6 << endl;
8 7 cout << 7 << endl;
9 8 cout << 8 << endl;
10 9 cout << 9 << endl;
11 10 false 循环退出

2、for与while

案例:输出1-10的数字。

  • while结构:

    int i = 1;
    while(i <= 10)
    {
      cout << i << endl;
      i++;
    }
    
  • for结构:

    for(int i=1; i<= 10; i++)
      cout << i << endl;
    

3、for循环变体

在for结构里,也可以把某个控制部分迁移到循环里面去,效果与原来类似,例如:

  • 初始状态迁移
    int i = 0;
    //保留一个分号
    for(; i <= 10; i++)
      .....
    
  • 表达式迁移
    //表达式迁移了,分号还在
    for(int i = 0;  ; i++)
    {
      cout << ....;
      //表达式放这里,注意退出条件和循环条件相反
      if (i > 10) break;
    }
    
  • 状态变化迁移:
    for(int i = 0; i <= 10; )
    {
       cout << ....;
       i++;  //状态变化放这里了
    }
    

四、for 与 if 结合

小明刚学习了for循环的知识,他很熟练的输出了0-10的数字,现在老师让他只输出0-10里面的偶数。

1、for循环的理解

for循环的循环体传入一个状态变量的多个值,例如1, 2, 3, 4....,如果执行语句是输出就直接把每个状态变量都输出了。

2、if 语句判断偶数

对于循环体传进来的每个状态变量,可以用if语句,使用关系表达式 i % 2 == 0判断是否是偶数,当状态变量是偶数时输出,否则跳过(到下一轮循环)。

for(......)
{
    if (关系表达式)
       //执行语句
}

如果if(关系表达式)不满足,则继续执行for的控制语句(i++,然后下一个)。

五、多重循环

小明问老师怎么才能学好编程?老师说:每周从周一到周日都要练习编程,每天编写五份代码,这样学习就会比较有效。

1、循环嵌套

循环体里面可以继续使用循环,一般用的比较多的是二重循环,例如:

while(条件1)
{
  //循环语句1
  while(条件2){
     //循环语句2
  }
}
for(循环条件1)
{
  //循环语句1
  for(循环条件2){
    //循环语句2
  }
}
do{
   //循环语句1
   for(循环条件2){
     //循环语句2
   }
}while(循环条件1);

2、例子

for(int i=1; i<=7; i++)
  {
    cout << "第" << i << "天:";
    for(int j=1; j<=5; j++)
      cout << "代码" << j << " ";
    cout << endl;
  }

输出:

第1天:代码1 代码2 代码3 代码4 代码5 
第2天:代码1 代码2 代码3 代码4 代码5 
第3天:代码1 代码2 代码3 代码4 代码5 
第4天:代码1 代码2 代码3 代码4 代码5 
第5天:代码1 代码2 代码3 代码4 代码5 
第6天:代码1 代码2 代码3 代码4 代码5 
第7天:代码1 代码2 代码3 代码4 代码5

第一行表示i=1时运行j=1..5。

3、循环次数

  • 外层循环的下标从1-7,共循环7次。
  • 内层循环的下标从1-5,每次外循环,内循环都要5次。
  • 总共循环次数是7*5 = 35 次。

多重循环次数

4、扩展理解

问题:如果三重循环i从1到10、j从1到20、k从1到5,总共循环次数是多少?

答案:10 * 20 * 5 = 500 次

WA  == wrong answer
TLE == Time limit error
AC  == answer correct
CE  == compile error

5、同余定理

模运算与基本四则运算有些相似,但是除法例外。其规则如下:

(a + b) % p = (a % p + b % p) % p

(1) (a - b) % p = (a % p - b % p) % p

(2) (a * b) % p = (a % p * b % p) % p

(3) a ^ b % p = ((a % p)^b) % p

(4) 结合律: ((a+b) % p + c) % p = (a + (b+c) % p) % p

(5) ((ab) % p * c)% p = (a * (bc) % p) % p

(6) 交换律: (a + b) % p = (b+a) % p

(7) (a * b) % p = (b * a) % p

(8) 分配律: ((a +b)% p * c) % p = ((a * c) % p + (b * c) % p) % p

重要定理

若a≡b (% p),则对于任意的c,都有(a + c) ≡ (b + c) (%p);

(10) 若a≡b (% p),则对于任意的c,都有(a * c) ≡ (b * c) (%p);

(11) 若a≡b (% p),c≡d (% p),

则 (a + c) ≡ (b + d) (%p),

(a - c) ≡ (b - d) (%p),

(a * c) ≡ (b * d) (%p),

(a / c) ≡ (b / d) (%p);