2.1 for循环
for循环的格式为:for(初始化;条件;调整) 循环体;
#include<stdio.h> int main(){ int i; for(i = 1;i<8;i++) printf("%d",i); printf("%d",i); //说是有这一行会报错 return 0; }建议尽量缩短变量的定义范围。例如,在for循环的初始化部分定义循环变量。
#include<stdio.h> int main(){ int i; for(i=1;i<6;i++) printf("%d\n",i); printf("%d\n",i); for(i=1;i<6;i++) return 0; }Visual C++6.0等早期编译器允许在循环体之后访问i,但这样,如果再写一个“for(int i = 0;i<n;i++)"则会出现i定义的错误。
但是
#include<stdio.h> int main(){ int i; for(i=1;i<6;i++) printf("%d\n",i); printf("%d\n",i); for(int i=0;i<6;i++) return 0; }没有出现什么报错嘞?
#include<stdio.h> int main(){ for(int i=1;i<6;i++) printf("%d\n",i); printf("%d\n",i); for(int i=0;i<6;i++) return 0; }是我错了这样就会像书本上说的报错了.(还是讲究作用范围)
不拘一格的使用伪代码来思考问题和描述算法是一种值得推荐的做法。
判断是否为平方数:
我的代码:
#include<stdio.h> #include<math.h> int main(){ int a,b,c,e; float d; scanf("%d%d",&a,&b); c = 1100*a+11*b; d = sqrt(c); e = d; if(e==d) printf("%d是平方数",c); return 0; }具体的题目是找出满足AABB形式的完全平方数,我完成以上的代码后AI告诉我,浮点数的运算会有误差因此这个开方的办法行不通,下面是另一种办法是用平方根去推完成平方数。
#include<stdio.h> int main(){ int a; int m = 0; for(m;m*m<10000;m++){ if(m*m > 1000){ a = m*m; int qian = a / 1000; // 千位 int bai = a / 100 % 10; // 百位 int shi = a / 10 % 10; // 十位 int ge = a % 10; // 个位 if(qian == bai && shi == ge) printf("%d是完全平方数",a); } } return 0; } //能正常运行出结果7744以下是课本上的代码
#include<stdio.h> int mian(){ for(int x = 1; ;x++) { int n = x * x; if(n<1000) continue; if(n>9999) break; int hi = b/100; int lo = n%100; if(hi/10 == hi%10 && lo/10 == lo%10) printf("%d\n",n); } return 0; }在C语言中,continue和break是控制循环语句执行流程的关键字,主要用于for、while和do-while循环中。
break用于立即终止当前所在的循环或switch语句,程序会继续执行循环或switch之后的代码。
- 在循环中使用
break会直接跳出整个循环,不再执行循环内剩余的语句。 - 在
switch中使用break会跳出当前的case分支,防止“穿透”到下一个case。
continue 的用法
continue用于跳过当前循环的剩余部分,直接进入下一次循环的条件判断或迭代。
- 在
for循环中,continue会跳到迭代部分(如i++)后再判断条件。 - 在
while或do-while循环中,continue会直接跳到条件判断部分。
两者区别:
continue 的用法
continue用于跳过当前循环的剩余部分,直接进入下一次循环的条件判断或迭代。
- 在
for循环中,continue会跳到迭代部分(如i++)后再判断条件。 - 在
while或do-while循环中,continue会直接跳到条件判断部分。
2.2while循环和do-while循环
猜想,输入一个大于1的自然数,若n为奇数则把n变为3n+1否则变为n的一半,经过若干次这样的变换结果一定等于1,但是问输入一个数求变换次数。
#include<stdio.h> int n; int s = 0; scanf("%d",&n); while(n!=1){ s++; if(n%2==0) n = n/2; else n=3*n+1; } printf("%d",s); return 0; } //通过实例输入3 输出7.正确。欧,不不不对,疏忽了,这是算法书上的:
#include<stdio.h> int main() { int n,count = 0; scanf("%d",&n); while(n>1) //这点我疏忽了, 题目有说须有体现 { if(n%2==1) n = n*3+1; //开始我写成了3n+1,注意乘法之间须有乘法符号 else n/=2; count++; } printf("%d/n",count); return 0; }书上说,当输入为987654321时,结果为1(但是我的电脑上就没显示结果,像是算不出来一样),这明显是错误的。错就错在乘法那里可能数据溢出了,好我们在来回顾一下第一章里,int整数的大小很可能是-2147483648~2147483647,很可能就很讲究了因为C99中只规定了int至少是16位没有规定具体值,但是目前的比赛平台上int都是32位整数。
while循环的格式为“while(条件)循环体;”。
例题2-3 计算4分之派=1-1/3+1/5-1/7+······,知道最后一项小于10的负六次方。
这是课本上的代码,我花了较长时间没能想出来是因为我不知道派怎么打出来,当我看到解答时就疑惑了,直接没有管这个四分之派。那么就是以小于10的负六次方为终止条件。
#include<stdio.h> int main(){ double sum = 0; for(int i = 0; ;i++) { double term = 1.0/ (i*2+1); if(i%2 == 0) sum += term; else sum -=term; if (term < 1e-6) break; } printf("%.6f\n",sum); return 0; }我有do-while 写的解题代码:
double n, sum = 1.0; int i=1;//不能写在do里面 do { n = 1.0/(i*2+1);//注意要用1.0来除以 if(i%2==0) sum += n;//判断好该加还是改减 else sum -= n; i++;//do-while 本身就是个循环,不要在里面再写一个for循环(我开始就犯了这样的错误) } while(n>(1e-6));//注意加分号 printf("%.6f\n",sum); return 0;//0.785399do-while 循环的格式为“do{循环体}while(条件);其中循环体至少执行一次,每次执行完循环后判断 条件,满足时再继续循环。
阶乘之和的题目
阶乘之和是一个经典的编程练习题,通常要求计算 1! + 2! + 3! + ... + n! 的末六位。下面是我的代码:
#include<stdio.h> int main(){ const int mod = 1000000; int n,m=1,s=0; scanf("%d",&n); for(int i=1;i<=n;i++) { m=1; for(int j = 1;j<=i;j++) { m = (m * j) % mod; } s=(s+m)%mod; } printf("%d",s); return 0; }提示:要计算只包含加法、减法和乘法的整数表达式除以正整数 n 的余数,可以在每步计算之后对 n 取余,结果不变。
这句话的意思是:在计算一个只包含加、减、乘运算的整数表达式时,如果我们最终需要的是这个表达式的结果除以一个正整数 n 的余数(即结果对 n 取模),那么我们可以不必等到计算出整个表达式的最终结果后再取余,而是在每一步计算(每次加法、减法或乘法)之后,立即将中间结果对 n 取余,用这个余数继续参与后续计算,最终得到的余数与先算出完整结果再取余的结果是相同的。
为什么这样做?
- 防止溢出:在编程中,直接计算阶乘等大数可能会超出整数类型的表示范围(溢出)。每步取余可以保证中间结果始终在 0 到 n-1 之间,避免溢出。
- 提高效率:对于非常大的数,每步取余可以保持数字较小,计算更快。
这样太慢了,加上一个计时器,看看究竟有多慢。
#include<stdio.h> #include<time.h> int main(){ const int mod = 1000000; int n,m=1,s=0; scanf("%d",&n); for(int i=1;i<=n;i++) { m=1; for(int j = 1;j<=i;j++) { m = (m * j) % mod; } s=(s+m)%mod; } printf("%d",s); printf("Time used = %.2f\n",(double)clock() / CLOCKS_PER_SEC); return 0; }键盘输入的时间也会被计算在内,为了避免输入数据的时间影响测试结果,可以使用一种称为“管道”的小技巧:在Windows命令行下执行echo 20| abc,操作系统会自动把20输入,其中abc是程序名。
2.4 算法竞赛中的输入输出框架
例题2-5 数据统计
输入一些数,求出他们的最大值、最小值和平均值(保留三位小数)。输入保证这些数都是不超过1000的整数。
这里得注意一下,我们的要求是直接输入一系列整数,开始不知道会输入多少个整数。那么这该怎么办呢?这个我想了一下,我不会,只有跟着教材来进行学习。(以下代码有BUG)
#include<stdio.h> //有BUG int main(){ int x,n = 0, min,max,s = 0; while (scanf("%d",&x) == 1) { s+=x; if(x<min) min = x; if(x>max) max = x; n++; } printf("%d %d %.3f\n",min,max,(double)s/n); return 0; }我输入了一大串按了enter没有反应,回顾一下(scanf的输入格式是,空格,TAB和回车都是无关紧要的,那么我们应该怎么告诉他输入结束了呢?)
提示:在windows下,输入完毕后先按Rnter键,再按Ctrl+Z,最后再按Enter键即可结束。在Linux下,输入完毕后按Ctrl+D即可结束。
结果可得,但是你应该发现最大值是一个与输入无关的值,为什么?,因为变量max一开始就等于那个数,自然不能更新为更小的。
提示:变量在未赋值之前的值是不确定的。特别的,他不一定是0。
解决方法:把max的初始值定义成一个比较小的数,把min的初始值定义为一个比较大的数就行,或者先读取第一个数x,把max=min=x。
还有就是说,每次都要输入许多数,这样会很不方便,那么好,一个好的方法就是用文件————
把输入的数据保存在文件中,就不必每次输入了;也避免了输出太多一卷屏前面看不到的尴尬。使用文件最简单的方法是使用输入输出重定向,只需在main函数的入口处加入以下两条语句:
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout):
上述语句将使得scanf从文件input.txt读入 ,printf写入文件output.txt.事实上,不只是scanf和printf,所有读键盘、写屏幕输出的函数都将改用文件。尽管这样做很方便,但是不是所有的算法竞赛都允许用程序读写文件。