第四章 循环结构的程序设计
4.1、需要重复执行的程序
4.2、至少要执行一次的循环
4.3、已知循环次数用for语句
4.4、循环控制–简单的循环应用
- 什么问题需要循环程序解决
- 如何表达循环中的条件
- 如何构造循环控制流程?
- 典型的循环应用问题有哪些?
循环问题
- 求累加和:
- 找满足条件的数:最大数、最小数
- 分类问题:字符
- 数列问题
经典循环问题:
- 鸡兔同笼问题
- 梅森素数问题
- 有数列2/3、4/5、6/9、10/15……
- 输出n、m中能被3整除,且至少有一个数字是5的所有数。
- 求3-150中所有素数的和
- 有一个八层高的灯塔,每层所点灯数等于上一层的2倍,一共有765盏灯,求塔低灯数
(一)需要重复执行的程序 while()循环
while()循环实现先判断后循环(当型循环)
特点:
在循环入口处判断当条件为真时执行循环。
关系运算符比较的结果为逻辑真(true)或者逻辑假(false)
程序执行的结果为1,2,1
a =1;b=2;c=3;
while(a<b<c)
{
t=a;
a=b;
b =t;
c--;
}
printf("%d %d %d",a,b,c);
例子求平均值
从键盘输入10个整数,求这10个整数的和
(1)这十个数不是连续的累加和(任意数):
(2)有些情况是用累加器求连续的整数和(不是任意的数)
求任意的是个数的和
#include <stdio.h>
int main()
{
int count = 0;
int sum = 0;
int num;
while (count < 10)
{
count++;
printf("Enter the No.%d =",count);
scanf("%d",&num);
sum += num;
}
printf("Average=%d\n",sum/10);
return 0;
}
区别方法一与方法二
for循环求和
#include <stdio.h>
int main()
{
int sum = 0;
int count = 10;
float average = 0;
int num = 0;
for (int i = 0; i < count; i++)
{
printf("NO.%d--->",i);
scanf("%d",&num);
sum += num;
}
average = (float)sum / count;
printf("%f\n",average);
}
没有指定精度的时候,float的精确位数是6
格式说明符正确与否影响结果的正确性
do-while求和
#include <stdio.h>
int main()
{
int sum = 0;
float average = 0;
int i = 0;
int num = 0;
while (i < 10)
{
scanf("%d",&num);
sum += num;
++i;
}
average = (float)sum / 10;
printf("%lf", average);
}
求的是连续的累加和
#include <stdio.h>
int main()
{
int n = 1;
int sum = 0;
while(n<100)
{
sum += n;
n++;
printf("%d",sum);
}
(二)至少要执行一次 do-while
说明:
循环体至少要执行一次
**直到条件为假时,退出循
例子:
成绩录入并计算平均分成绩的有效性)
#include <stdio.h>
int main()
{
int s,b= 1;
do{
printf("输入第%d个成绩:",n);
scanf("%d",&s);
if(s<0||s>100)
printf("成绩无效,重新输入!\n");
else
{
printf("录入成功");
执行程序后,i,j, k的值是什么?i=5,j=4,k=6;
#include <stdio.h>
int main()
{
int a = 10;
int b = 5;
int c = 5;
int d = 5;
int i, j, k = 0;
for (; a > b; ++b)
i++;
while (a > ++c)
j++;
do
{
k++;
} while (a > d++);
return 0;
}
为什么是死循环啊?while的条件不是不对吗 ?
x = 3;
do
{
y = x--;
if (!y)
{
printf("x");
continue;
}
printf("#");
} while (1 <= x <= 2);
是死循环?
例子:测试录入速度
- 问题描述:
从键盘上录入英文文章并显示,记录输入字符的个数,直到输入结束标记时才停止。 - 问题分析:
由于不知道要输入的字符数量,只能靠结束标记停止循环
设:结束标记为字符#
#include <stdio.h>
#include <time.h>
int main()
{
char ch;
int n = 0;
time_t t1, t2;
time(&t1);//获取时间并存入变量
while (ch = getchar() != '#')
n++;
time(&t2);
printf("\n总的输入字符数:%d",n);
printf("\n平录入速度:%.2fs",1.0*n/(t2-t1));
return 0;
}
> 例子: N的阶乘n!
- 问题描述:输入n ,计算n的阶乘
- 问题分析:n! =1*2*….*(n-1)n
方法一:
#include <stdio.h>
int main()
{
int n = 0;
int sum = 1;
printf("求n的阶乘: ");
scanf("%d",&n);
for (int i = 1; i <= n; i++)
{
sum *= i;
}
printf("%d\n",sum);
}
方法二:n的阶乘n!
问题描述:
输入n,计算N的阶乘
问题分析
n!=1*2…*(n-1)*n
#include <stdio.h>
int main()
{
int n,t;
int result = 1;
scanf("%d",&n);
t = n;
if (n > 0)
{
do
{
result *= n;
n--;
} while (n);
}
printf("%d! = %d\n",t,result);
}
例子:字符分类统计
问题描述
从键盘上输入任意的字符,按下列规则进行分类计数。
问题分析:
第一类:‘0’‘1’‘2’‘3’‘4’‘5’‘6’‘7’‘8’‘9’
第二类:‘+’‘-’‘*’‘/’‘%’
第三类:其他的字符
当输入字符‘\’时先计数后停止接受输入。
#include <stdio.h>
int main()
{
int class1 = 0;
int class2 = 0;
int class3 = 0;
char ch;
do
{
ch = getchar();
switch (ch)
{
case '0':case '1':case '2': case '3':
case '4':case '5':case '6': case '7':
case '8':case '9':
class1++;
break;
case '+':case '-': case '*': case '/':
class2++;
break;
default:
class3++;
break;
}
} while (ch != '\\');
printf("\n class1 = %d,class2 = %d,class3 = %d\n", class1, class2, class3);
return 0;
}
从直接输入到IDE中得到测试结果,然后有正确的答案,但这样的效果真的好吗?我根本就不理解?所以我给记录下来了
main()
{
int a = 10;b=5;c=5;d=5;i=0;j=0;k= 0;
for( ; a>b;)
i++;
while(a>++c)
j++;
do
{
k++;
}while(a>d++);
}
x= 3;
do{
y = x--;
if(!y)
{
printf("x");
continue;
}while(1<=x<=2);
(三)已知循环的次数
求1到n的和?(求和问题)
从键盘输入n,计算1都n的和
#include <stdio.h>
int main()
{
int n, sum = 0;
int i = 0;
printf("Input n:\n");
scanf("%d",&n);
for (i = 0; i < n; i++)
{
sum += i;
}
printf("%d-->%d",i,sum);
return 0;
}
> 例子:分数数列: 1/2、2/3、3/4….前20项的和。
求分数的和时要考虑到数据类型的选择,不能用int
#include <stdio.h>
int main()
{
for(i = 1;i<=20;i++)
{
sum += i/i+1;
}
printf("%d\n",sum);
return 0;
}
1、为什么要乘以1.0
2、为什么要多加括号
#include <stdio.h>
int main()
{
double sum = 0;
for (int i = 1; i <= 3; i++)
{
sum += i*1.0 / (i + 1);
}
printf("%lf",sum);
return 0;
}
求和问题
例子:斐波那契数列
斐波那契数列 :1,1,2,3,5,8,13,21,34,55,89,144。。
通项公式:
a1 = 1 a2 =1
an=a(n-1) +a(n-2)(n>=3,n属于正整数N)后一个数是前两个数和
输入n,输入前n项,及前n项的和
#include <stdio.h>
int main()
{
int n ,t,a1 = 1;
a2 = 1;s= 0;
printf("%d %d",a1,a2);
for(int i = 0;i <n;i++)
{
t=a1+a2;
printf("%d",t);
s=s+t;
a1 = a2;
a2 = t;
}
printf("s=%d ",s);
return 0;
}
#include <stdio.h>
int main()
{
int a1, a2 = 1;
int num = 0;
int sum = 0;
int temp = 0;
printf("输入项数:");
scanf("%d",&num);
printf("%d %d",a1,a2);
for (int i = 3; i <= num; i++)
{
temp = a1 + a2;
printf("%d",temp);
sum = sum + temp;
a1 = a2;
a2 = temp;
}
printf("sum=%d \n", sum);
return 0;
}
4.4 循环控制 —简单的应用
循环的应用
例子:打印100~200之间所有能被3或7整除的数
#include <stdio.h>
int main()
{
for (int i = 100; i < 200; i++)
{
if (i % 3 == 0 || i % 7 == 0)
printf("%d\n", i);
}
return 0;
}
(2)尝试使用while循环实现:
控制控制的简单应用
水仙花数
- 问题描述:
打印出所有的水仙花
- 问题分析:
水仙花数是指一个三位数,它的每个位上的数字的3次幂之和等于它本身。
153 = 1*1*1+5*5*5+3*3*3
问题的关键是如何取得三位数的每个位数
#include <stdio.h>
int main()
{
int a, b, c;
for (int i = 100; i < 1000; i++)
{
a = i % 10;
b = i / 10 % 10;
c = i / 100;
if (i == a*a*a + b*b*b + c*c*c)
printf("%d\n", i);
}
return 0;
}
打印时出现问题,看似不会出现问题还是出现了问题
把等号==写成了=
最重要的原因是自己竟然没有耐心找出错误,总觉得自己没有错位。
例子:判断素数
输入X,判断x是否为素数:
只能被1和它本身整除的数为素数
#include <stdio.h>
int main()
{
int a1, a2 = 1;
int num = 0;
int sum = 0;
int temp = 0;
printf("输入项数:");
scanf("%d",&num);
printf("%d %d",a1,a2);
for (int i = 3; i <= num; i++)
{
temp = a1 + a2;
printf("%d",temp);
sum = sum + temp;
a1 = a2;
a2 = temp;
}
printf("sum=%d \n", sum);
return 0;
}
例子:大数分解
从键盘上输入一个大于1的整数,通过算法将该整数分解为若干质数因子的乘积
a=a/i 找到下一个因子之后获得的新a
(1)任何一个大数都可以分解为若干个素数的乘积
(2)什么是因子:能被整除的数都是
(3)什么是素数
(4)凡是能被这个数整除的数都是这个数的因子
(5)这个数就是这些因子的乘积
被除数能被除数整除
#include <stdio.h>
int main()
{
int a, i;
scanf("%d",&a);
for (i = 2; a != 1;)
{
if (a%i == 0)
{
a = a / i;
printf("%d ", i);
}
else
i++;
}
}
第六周 循环结构的程序设计
4.5 循环的嵌套
4.6 break和continue;
4.7 需要用循环解决的问题的讨论
4.5 循环的嵌套(一)循环的嵌套—构成平面图案
打印九九乘法表
#include <stdio.h>
int main()
{
int j, i;
for (int i = 1; i <= 9; i++)
{
printf("\t第%d列 ", i);
}
printf("\n");
for (i = 1; i <= 9; i++)
{
printf("第%d行", i);
for (j = 1; j <= 9; j++)
{
printf(" %2d*%d=%d ", i, j, i*j);
}
printf("\n");
}
return 0;
}
内循环的终值与外循环的循环控制变量有关系
打印三角图案
打印的内部是实心的
#include <stdio.h>
int main()
{
int i, j, n = 0;
printf("需要打印多少行: ");
scanf("%d",&n);
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n - i; j++)
{
printf(" ");
}
for (j = 1; j <= 2 * i - 1; j++)
{
printf("*");
}
printf("\n");
}
return 0;
}
例子:打印三角图案
打印的内补是空的只有边
#include <stdio.h>
int main()
{
int i, j, n;
printf("需要打印的行数:");
scanf("%d",&n);
for (i = 1; i <= n; i++)
{
for (j = 1; j <= n - i; j++)
{
printf(" ");
}
printf("*");
for (j = 1; j <= 2 * i - 3;j++);
{
printf(" ");
}
if(i!=1)//逆向思维
printf("*");
printf("\n");
}
return 0;
}
#include <stdio.h>
int main()
{
int i, j;
float s;
for (i = 6; i > 4; i--)
{
s = 0.0;
for (j = i; j > 3; j--)
s = s + i*j;
}
printf("%f\n",s);
return 0;
}
break语句和continue语句
break的功能
在switch语句中结束case子句在控制转到switch语句之外
在循环体中使用,结束当前的循环过程,使控制转移到循环语句之外的下一条语句。
break再讨论
break在循环体中的作用是:中断当前所在的这一级循环的循环
break再讨论;
找出最大的素数
输入n,输出1到n之间的最大的素数
问题分析:
n =1,2,3,4,5,6,7,8,9,数据域
i =1,2,3,4,5,6,7,
两处需要中断:
1、外循环时找到了
2、内循环中当前数废除了
continue的用法
continue的功能
- continue语句仅能在循环语句中使用。
- 作用是仅跳过当前这一次循环
- 对于for语句将控制转到执行增量和条件测试部分
- 对于while和do-while语句,将控制转到条件测试部分
循环中断与循环继续
例子:输入10个整数,统计其中的正数的个数及平均值。
循环的综合应用-数的排列组合问题
鸡兔同笼
#include <stdio.h>
int main()
{
int x, y;
int n = 0;
for (x=1;x<35;x++)
{
for (y=1;y<35;y++)
{
if (((x + y) == 35) && ((2 * x + 4 * y) == 94))
printf("鸡:%d 兔:%d\n",x,y);
n++;
}
}
printf("n=%d\n",n);
return 0;
}
例子:取出1~9中的4个互不相同的数 ,使他们的和为12,用穷举法输出所有满足条件的4个数的排列
讨论:
(1)注意到:互不相同的4个数均小于或等于6.
(2)把所有的判断均放在最内层循环不合理,应放到与之相关的循环中,i==j的判断,只有和i、j有关,放在j循环中只判断9*9=81次,而放在最内存中判断9*9*9*9=6561次
(3)因为i,j,k和I的和为12,所以所有的I=12-i-j-k,这样就减少一重循环。不过,要注意I>0且I<7,因为i+j+k最少是1、2、3的组合,即6.
分析:若i,j,k,I分别代表4个数,列出它们所有的排列,从中找出符合条件的i,j,K和I(i+j+k+i=12,且这四个数互不相同)
#include <stdio.h>
int main()
{
int i, j, k, l, n = 0,m=0;
for (i = 1; i < 10; i++)
{
for (j = 1; j < 10; j++)
{
for (k = 1; k < 10; k++)
{
for (l = 1; l < 10; l++)
{
m++;
if (i == j || i == k || i == 1 || j == k || j == 1 || k == 1)
continue;
if (i + j + k + l != 12)
continue;
printf("{%d,%d,%d,%d}",i,j,k,l);
if (n % 5 == 0)
printf("\n");
}
printf("\n\n%d,%d\n", n, m);
return 0;
}
}
}
}
优化之后的程序是:
#include <stdio.h>
int main()
{
int i, j, k, l, n = 0, m = 0;
for (i = 1; i < 7; i++)
{
for (j = 1; j < 7; j++)
{
if (i == j)
continue;
for (k = 1; k < 7; k++)
{
m++;
l = 12 - i - j - k;
if (i == k || j == k || l == i || l == j || l == k)
continue;
if (l <= 0 || l > 7)
continue;
n++;
printf("{%d,%d,%d,%d}",i,j,k,l);
if (n % 5 == 0)
printf("\n");
}
}
}
printf("\n\n%d,%d",n,m);
}
求555555的约数中最大的三位数是多少?
思路:从?最大的约束开始找,找到为止。
#include <stdio.h>
int main()
{
int j;
long n;
printf("please input number: ");
scanf("%ld",&n);
for (j = 999; j >= 100; j--)
{
if (n%j == 0)//若能够整除j,则j就是约数
{
printf("3digits in %ld = %d\n",n,j);
break;//控制退出循环
}
return 0;
}
}
求14的13次方数的最后三位数
设计求x的y次方末尾三位数的逼
#include <stdio.h>
int main()
{
int i = 1;
int x, y;
int a = 1;
printf("Input X and Y: ");
scanf("%d%d", &x, &y);
while (i < y)
{
a = a*x % 1000;
i++;
}
printf("3 digits is: ");
printf("%d\n",a%1000);
}
打印空心图案
输入n值,输出如图所示图形
Z
Y X
W V
U T
S R
Q P
O N
M L
K
n=5
#include <stdio.h>
int main()
{
char c = 'Z';
int i, j, n;
printf("\nPlease Enter n:");
scanf("%d",&n);
for (i = 1; i <= n; i++)//控制输出的行数
{//打印最后一个字符之前的空格和字符
for (j = 1; j <= n + i - 2; j++)
if (j == n - i + 1)
printf("%c", c--);
else
printf(" ");
printf("%c\n",c--);
}
for (i = 1; i < n; i++)
{
for (j = 1; j < 2 * (n - 1) - i; j++)
if (j == i + 1)
printf("%c", c--);
else
printf(" ");
printf("%c\n",c--);
}
}
如果打印的图案中出现问号,那么是未显示的字符(键盘上敲不进去的字符)
i <= n
打印n行的话,就应该包含n的,不应该把等于n给忽略掉。
if (j == n - i + 1)
总是把测试等与数学里面的等号混淆
if (j == i + 1)
总是把测试等与数学里面的等号混淆
j <= 2 * (n - 1) - i
内循环的终值总是和外循环的控制变量有关系
j <= n + i - 2
内循环的终值总是和外循环的控制变量有关系
打印图形
以下图形用什么算法实现程序最简单?你会考虑哪些测试用例来保证程序的正确性和坚固性?请给出你的实现程序。(图中n=5)
打印空心图形
输入n值,输出如图所示边长为n的空心正六边型(n=5)。
程序如下,但这个程序运行结果不正确,你可以修改吗?
#include<stdio.h>
int main( )
{ int i, j, n;
printf("\nPlease Enter n:");
scanf ("%d", &n);
for(i=1;i<=n;i++)
{ for(j=1;j<=2*n-i;j++)
if(j==n-i+1 || j>n-i+1 && i==1)
printf("*");
else printf(" ");
}
for(i=1;i<n;i++)
{ for(j=1;j<=3*(n-1)-i;j++)
if(j==i+1 || j>i+1 && i==n-1)
printf("*");
else printf(" ");
printf("*\n");
}
}
来自课件“讨论题3”
已知2014年1月1日是星期三,你可以编写程序在屏幕上输出2015年的年历吗?
提示:关于闰年的计算方法是,如果某年的年号能被400除尽, 或能被4除尽但不能被100除尽,则这一年就是闰年。