循环控制
第一部分 -循环控制
素数是只能被1和自己整除的数,素数不包括1。
判断是否为素数的程序;算法的思路就是拿很多的数去除这个数,如只能被1和本身整除,那这个数就是素数。设一个数位x,x%i==0;这个关系表达式的意思就是,x 对 i 进行取余如果可以被整除那结果就为0。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int x;
printf("请输入一个需要判断的数字\n");
scanf("%d", &x);
int i;
int isprine = 1;
for (i = 2; i < x;i++){
if (x%i == 0){
isprine = 0;//这一步是用来证伪的。也就是说在1<i<x这个范围中,
break; //当x对i取余时如果有能够整除的数字,那就说明x对i取余等于0
//也就说明不是素数,就可以把0赋值给isprine。进行下面的if的条件判断。
}
}
if (isprine == 1){
printf("是素数\n");
}
else{
printf("不是素数\n");
}
return 0;
}
break和continue的区别:break是跳出循环,continue是跳过这一轮循环,进入下一轮循环,但是循环还在执行。重点是break和continue这两个都是用在循环里的。是不能单独的用在条件判断语句中,这样是会报错的。
循环控制
第一部分 -嵌套的循环--找素数
循环的里面还是一个循环,这个就嵌套循环。嵌套循环的要记住外层与内层的循环控制条件是不能一样的。
如何用一段程序来实现输出100以内的素数。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int y;
printf("输入需要判断的最大数字\n");
scanf("%d", &y);
int x;
for (x = 2; x < y; x++)
{
int i;
int isprins = 1;
for (i = 2; i < x; i++)
{
if (x%i == 0)
{
isprins = 0;
break;
}
}
if (isprins == 1){
printf("%d,", x);
}
}
printf("\n");
return 0;
}
这里要注意isprins的位置要放在紧挨着内层for循环的外面。
如何输出50个素数呢,显然这里的循环次数是不确定,所以我们可以使用while循环,当然我们也可使用for循环来实现,但是使用for循环可能不太容易让别人读懂。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int count=0;
int x=2;
while (count < 50)
{
int i;
int isprime = 1;
for (i = 2; i < x; i++)
{
if (x%i == 0)
{
isprime = 0;
break;
}
}
if (isprime == 1){
printf("%d,", x);
count++;
}
x++;
}
printf("输出了%d个素数\n",count);
return 0;
}
采用for循环来实现输出100个素数
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int count=0;
int x=2;
for (x = 2; count < 100;x++)
{
int i;
int isprins = 1;
for (i = 2; i < x; i++)
{
if (x%i == 0)
{
isprins = 0;
break;
}
}
if (isprins == 1){
printf("%d,", x);
count++;
}
}
printf("输出了%d个素数\n",count);
return 0;
}
第二部分 -从嵌套循环中跳出--凑硬币
凑硬币程序如下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int x;
int one, two, five;
printf("请输入需要凑的金额\n");
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", x, one, two, five);
}
}
}
}
return 0;
}
这个程序给出了能凑出所求的所有情况。那么该怎样让这个程序只输出一种情况呢。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int x;
int exit = 0;
int one, two, five;
printf("请输入需要凑的金额\n");
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", x, one, two, five);
exit = 1;
break;
}
}
if (exit == 1) break;
}
if (exit == 1) break;
}
return 0;
}
上面的解决方案是用 if 条件判断和break来解决的,这种方式叫接力break。还有一种方法就是运用goto语句来解决,如下
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int x;
int exit = 0;
int one, two, five;
printf("请输入需要凑的金额\n");
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", x, one, two, five);
goto out;
}
}
}
}
out:
return 0;
}
goto语句,执行到goto时,该语句可以跳到goto后面那个out所指的地方。但是goto语句只建议用在上面这种循环的情况,其他地方不要用,因为使用goto语句会破坏整个程序的结构性,跳来跳去的。
循环控制
第一部分 -前n项求和
1+1/2+1/3+1/4+1/5+....+1/n,求这种运算首先想到的是,这是一个有限的循环,所以我们首先想到的是运用for循环。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int i;
int n;
scanf("%d", &n);
double sum=0.0;
for (i = 1; i < n; i++)
{
sum = sum + 1.0 / i;
}
printf("%lf", sum);
return 0;
}
那么对于交错的n项求和该怎么处理呢,可以添加一个变量,让这个变量每循环一次就改变一下正负。如下
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int i;
int n;
scanf("%d", &n);
double sum=0.0;
int sign = 1;
for (i = 1; i < n; i++)
{
sum = sum + sign*1.0 / i;
sign = -sign;
}
printf("%lf", sum);
return 0;
}
第二部分 -求最大公约数
求最大公约数有两种方式:一种是枚举,另一种是辗转相除法
枚举的方式求最大公约数:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int x, y;
printf("请输入两个数字\n");
scanf("%d %d", &x, &y);
int min;
if (x>y){
min = y;
}
else{
min = x;
}
int i;
int ret = 0;
for (i = 1; i <= min; i++){
if (x%i == 0){
if (y%i == 0){
ret = i;
}
}
}
printf("%d和%d的最大公约数为%d\n", x, y, ret);
//这个之所以是最大公约数,是因为ret会不断地被替换掉,所输出的最后一个数就是最大的公约数。
return 0;
}
使用枚举的方法简单但是效率不高,因为要罗列出所有的情况。
辗转相除法求最大公约数:
算法如下:
第一步 如果b等于0,计算结束,a就是最大公约数
第二步 否则,计算a除以b的余数,让a等于b,而b等于那个余数;
第三步 回到第一步。
程序如下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
/*
第一步 如果b等于0,计算结束,a就是最大公约数;
第二步 否则,计算a除以b的余数,让a等于b,而b等于那个余数;
第三步 回到第一步。
假设求a=12,b=18的最大公约数。
a b t(a%b)
12 18 12
18 12 6
12 6 0
6 0
*/
int main()
{
int a, b;
int t;
printf("请输入两个数字\n");
scanf("%d %d", &a, &b);
while (b != 0){
t = a%b;
a = b;
b = t;
}
printf("最大公约数为%d\n", x);
return 0;
}
第三部分 -整数分解
正序分解一个整数:
- 输入一个非负整数,正序输出它的每一位数字
- 输入12345
- 输出1 2 3 4 5
下面的这个程序可以输出逆序后的数,但是是逆序的。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int x;
scanf("%d", &x);
do{
int d = x % 10;
printf("%d", d);
if (x >9){
printf(" ");
}
x /= 10;
} while (x > 0);
return 0;
}
怎样把分解后逆序的数字调整为正序呢,我们的方法可以是在没有分解之前先把数字逆序输出,这时的逆序输出是逆序但是没有分解。然后再把上面的程序放到下面执行,就可以得到正序分解后的数字。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int x;
printf("输数\n");
scanf("%d", &x);
int d;
int t=0;
do{
d = x % 10;
t = t * 10 + d;
x /= 10;
} while (x > 0);
printf("t=%d\n", t);
int y;
do{
y = t % 10;//把该数的最后一位单独拿来
printf("%d", y);//再任何语句后面打印都不影响计算。
if (t > 9){
printf(" ");
}
t /= 10; //把该数的最后一位去掉
} while (t > 0);//判断去掉后的数字是否大于零,是否循环。
return 0;
}
但是上面正序分解整数的方法对于x=700,这样的数就不适用了。因为正序分解后的数为7。这个问题先保留。我们再看一种整数正序分解的方法,看能不能得到一些启示。
前面我们介绍过如何得到一个任意位数数字的最高位和最低位的数字:假如x=13425,我们可以让x/10000得到最高位数字1,可以让x%10000,也就是x/10000=1余3425,x%10000=3425。以此类推。
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int x;
printf("输数\n");
scanf("%d", &x);
int mask = 10000;
do{
int d = x / mask;
printf("%d", d);
if (x > 9){
printf(" ");
}
x %= mask;
mask /= 10;
} while (x > 0);
return 0;
}
上述程序同样可以让一个任意位数的数字正序分解。但是对于700,同样也是只能输出7。
第一个问题是怎样让700中的00输出,第二个问题是怎样让0与0之间有一个空格。
这段程序的好处就是我们可以用mask替换x的值,用mask作为do while循环的判断条件。程序如下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int x;
printf("输数\n");
scanf("%d", &x);
//判断一下某个数字的位数
int t = x;
int mask=1;
do{
x /= 10;
mask *= 10;
} while (x > 9);
printf("%d\n", mask);
do{
int d = t / mask;
printf("%d", d);
if (mask > 9){
printf(" ");
}
t %= mask;
mask /= 10;
} while (mask > 0);
return 0;
}
这个程序的问题是不能对10或1做出正确的输出,所以还要修改,这个就牵涉到什么时候用while循环,什么时候用do while 循环了,改正后的程序如下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
int x;
printf("输数\n");
scanf("%d", &x);
//判断一下某个数字的位数
int t = x;
int mask=1;
while (x > 9){
x /= 10;
mask *= 10;
}
printf("%d\n", mask);
do{
int d = t / mask;
printf("%d", d);
if (mask > 9){
printf(" ");
}
t %= mask;
mask /= 10;
} while (mask > 0);
return 0;
}
回顾一下学习过的循环类型:
while循环:解决某个问题时,不知道要循环多少次才能得出结果时,就用while循环。特点先判断后循环。
do while循环:先执行一次循环之后在进行判断是否继续执行循环。特点就是先执行在判断。
for循环:解决某个问题时,清楚要循环多少次能得出结果,就用for循环。