5.1 循环控制
5.1.1 循环控制
写一段程序判断一个数是不是素数
int x;
scanf("%d", &x);
int i;
int isPrime=1;//x是素数
for(i=2;i<x;i++){
if(x%i==0){
isPrime=0;
}
}
if(isPrime==1){
printf("是素数\n");
}else{
printf("不是素数\n");
}
return 0;
程序可以正确判断一个数是否是素数。但是存在问题。假设输入的x是6,当i=2时,6%2=0,已经可以判断6不是素数,但是循环还会继续进行下去,直到i=6结束循环,所以可以对程序做出改动,增添一个break。
int x;
scanf("%d", &x);
int i;
int isPrime=1;//x是素数
for(i=2;i<x;i++){
if(x%i==0){
isPrime=0;
break;
}
}
if(isPrime==1){
printf("是素数\n");
}else{
printf("不是素数\n");
}
return 0;
- break:跳出循环;
- continue:跳过循环这一轮剩下的语句进入下一轮。
还有一种方法
int x;
scanf("%d", &x);
int i;
int isPrime=1;//x是素数
for(i=2;i<x;i++){
if(x%i==0){
isPrime=0;
}
}
if(isPrime==1){
printf("是素数\n");
}else{
printf("不是素数\n");
}
return 0;
程序可以正确判断一个数是否是素数。但是存在问题。假设输入的x是6,当i=2时,6%2=0,已经可以判断6不是素数,但是循环还会继续进行下去,直到i=6结束循环,所以可以对程序做出改动,增添一个break。
int x;
scanf("%d", &x);
int i;
//int isPrime=1;//x是素数
for(i=2;i<x;i++){
if(x%i==0){
//isPrime=0;
break;
}
}
//if(isPrime==1){
if(i<x){
printf("不是素数\n");
}else{
printf("是素数\n");
}
return 0;
这种方法是有害的(?)
5.2 多重循环
5.2.1 嵌套循环
写一段程序,输出100以内的素数
int x;
scanf("%d", &x);
int i;
int isPrime=1;//x是素数
for(i=2;i<x;i++){
if(x%i==0){
isPrime=0;
}
}
if(isPrime==1){
printf("是素数\n");
}else{
printf("不是素数\n");
}
return 0;
程序可以正确判断一个数是否是素数。但是存在问题。假设输入的x是6,当i=2时,6%2=0,已经可以判断6不是素数,但是循环还会继续进行下去,直到i=6结束循环,所以可以对程序做出改动,增添一个break。
int x;
for(x=2;x<100;x++)
{
int i;
int isPrime=1;//x是素数
for(i=2;i<x;i++){
if(x%i==0){
isPrime=0;
break;
}
}
if(isPrime==1){
printf("%d\n", x);
}
}
printf("\")
return 0;
在这段程序中, 循环中出现了循环。要注意的是,外层循环和内层循环的变量不要搞混。
再写一段程序可以输出前50个素数。
int x;
int x=2;
int cnt=50;
//while(cnt<50)
for(x=2;cnt<50;x++)
{
int i;
int isPrime=1;//x是素数
for(i=2;i<x;i++){
if(x%i==0){
isPrime=0;
break;
}
}
if(isPrime==1){
printf("%d\n", x);
cnt++;
}
//x++;
}
printf("\n")
return 0;
5.2.2 跳出嵌套循环
用代码求出如何用一角、两角和五角硬币凑成十元以下的金额。
int x;
int one, two, five;
int exit=0;
scanf("%d", &x);
for(one=1;one<x*10;one++){
for(two=1;two<x*10/2;two++){
for(five=1;five<x*10/5;five++){
if(one+two*2+five*5==x*10){
printf("可以用%d个一角加%d个两角加%d个五角得到%d元\n",
one, two, five, x);
}
}
}
}
输出
2
可以用1个一角加2个两角加3个五角得到2元
可以用1个一角加7个两角加1个五角得到2元
可以用2个一角加4个两角加2个五角得到2元
可以用3个一角加1个两角加3个五角得到2元
可以用3个一角加6个两角加1个五角得到2元
可以用4个一角加3个两角加2个五角得到2元
可以用5个一角加5个两角加1个五角得到2元
可以用6个一角加2个两角加2个五角得到2元
可以用7个一角加4个两角加1个五角得到2元
可以用8个一角加1个两角加2个五角得到2元
可以用9个一角加3个两角加1个五角得到2元
可以用11个一角加2个两角加1个五角得到2元
可以用13个一角加1个两角加1个五角得到2元
如果我们想得到一个结果就足够,那么该如何修改代码呢?
如果这样修改
int x;
int one, two, five;
int exit=0;
scanf("%d", &x);
for(one=1;one<x*10;one++){
for(two=1;two<x*10/2;two++){
for(five=1;five<x*10/5;five++){
if(one+two*2+five*5==x*10){
printf("可以用%d个一角加%d个两角加%d个五角得到%d元\n",
one, two, five, x);
break;
}
}
}
}
这样得到的结果和上一条一样。因为当进入第三层循环后break会跳出第三层循环,进行下一次第二层循环,而即使第三层循环执行到底也不会有多余的输出,因为前两层一定固定第三层如果有解一定唯一,所以直接进行下一次二层循环不会漏解。
- break和continue只能对它所在的那一层循环做。
这样修改呢?
int x;
int one, two, five;
int exit=0;
scanf("%d", &x);
for(one=1;one<x*10;one++){
for(two=1;two<x*10/2;two++){
for(five=1;five<x*10/5;five++){
if(one+two*2+five*5==x*10){
printf("可以用%d个一角加%d个两角加%d个五角得到%d元\n",
one, two, five, x);
break;
}
}
break;
}
break;
}
这样也不行,因为这样就会导致不论以怎样的方式跳出第三层循环,第二层第一层都会依次跳出。
正确的代码是这样的
int x;
int one, two, five;
int exit=0;
scanf("%d", &x);
for(one=1;one<x*10;one++){
for(two=1;two<x*10/2;two++){
for(five=1;five<x*10/5;five++){
if(one+two*2+five*5==x*10){
printf("可以用%d个一角加%d个两角加%d个五角得到%d元\n",
one, two, five, x);
exit=1;
break;
}
}
if(exit==1) break;
}
if (exit==1 )break;
}
这种情况叫做接力break。
还有另一种正确的方式
int x;
int one, two, five;
scanf("%d", &x);
for(one=1;one<x*10;one++){
for(two=1;two<x*10/2;two++){
for(five=1;five<x*10/5;five++){
if(one+two*2+five*5==x*10){
printf("可以用%d个一角加%d个两角加%d个五角得到%d元\n",
one, two, five, x);
goto out;
}
}
}
}
out:
goto一般只用在跳出多层循环的情况,它被认为会破坏程序的结构性。
5.3 循环应用
5.3.1 前n项求和
求和1+1/2+1/3+···1/n
int n;
int i;
double sum=0.0;
scanf("%d", &n);
for(i=1;i<=n;i++){
sum+=1.0/i
}
printf("f(%d)=%f", n, sum);
求和1-1/2-1/3+···1/n
int n;
int i;
double sum=0.0;
double sign=1.0;//int sign=1;
scanf("%d", &n);
for(i=1;i<=n;i++){
sum+=sign/i;//sum+=sign*1.0/i;
sign=-sign;
}
5.3.2 求最大公约数
输入两个数a和b,输出最大公约数
算法一:枚举
- 设t=2;
- 如果u和v都能被t整除,则记下这个t;
- t加1后重复第2步,直到t等于u或v;
- 曾经记下最大的可以同时整除u和v的t就是最大公约数。
代码如下
int a, b;
int min;
scanf("%d %d", &a, &b);
if(a<b){
min=a;
}else{
min=b;
}
int ret=0;
int i;
for(i=1;i<min;i++){
if(a%i==0){
if(b%i==0){
ret=i;
}
}
}
printf("%d和%d的最大公约数是%d.\n", a, b, ret);
算法二:辗转相除法
- 如果b等于0,计算结束,a就是最大公约数;
- 否则,计算a除以b的余数,让a等于b,而b等于那个余数;
- 回到第一步。
代码如下
int a, b;
int t;
scanf("%d %d", &a, &b);
while(b!=0){
t=a%b;
a=b;
b=t;
}
printf("gcd=%d\n", a);
5.3.3 整数分解
输入一个非负整数,正序输出它的每一位数字
例:
- 输入:12345
- 输出:1 2 3 4 5
代码如下
Int x;
scanf("%d", &x);
int mask=1;
int t=x;
while(t>9){
t/=10;
mask*=10;
}
printf("x=%d, mask=%d\n", x, mask);
do{
int d=x/mask;
printf("%d", d);
if(mask>9){
printf(" ");
}
x%=mask;
mask/=10;
}while(mask>0);
printf("\n");