2.循环结构程序设计

内容

for 循环

  1. 输出1,2,3,...,n的值
    #include<stdio.h>
    
    int main()
    {
        int n;
        scanf("%d", &n);
        for(int i=1; i<=n; i++){
            printf("%d\n", i);
        }
        return 0;   
    } 
    
    1. for循环的格式: for(初始化; 条件; 调整) 循环体;
    2. 注意理解for循环的执行过程
    3. 在循环内定义变量的i,循环体外不可见。尽量缩小变量定义的范围。
  2. 输出所有形如aabb的4位完全平方数。
    #include<stdio.h>
    #include<math.h>
    
    int main()
    {
        // 两层循环嵌套 
        for(int i=1; i<10; i++){
            for(int j=0; j<10; j++){
                // 得到 aabb 这种数 
                int n = i*1100+j*11;
                // 开方,四舍五入 
                int m = floor(sqrt(n) + 0.5);
                if(m*m == n){
                printf("%d\n", n);
                } 
            }
        }
        return 0;   
    }
    
    1. 伪代码,实际应用中,不需要太拘泥于伪代码的格式,主要目标是描述算法梗概,避开细节,启发思路。
    2. 浮点运算可能存在误差。在进行浮点数比较时,应考虑到浮点误差。
    // 解答二 枚举法
    #include<stdio.h>
    #include<math.h>
    
    int main()
    {
        for(int i=1; ; i++){
            int x = i*i;
            if(x < 1000){
                continue;
            }
            if(x > 9999){
                break;
            }
            int hi = x/100;
            int low = x%100;
            if(hi/10 == hi%10  && low/10 == low%10){
                printf("%d\n", x);
            }
        } 
        return 0;   
    }
    
    注:把所有平方数都列举出来,选出满足条件的,四位数,aabb型。

while循环和do-while循环

  1. 3n+1问题
    对于任意大于1的自然数n,若n为奇数,则将n变为3n+1,否则变为n的一半。经过若干次这样的变换,一定会使n变为1。求变换次数。
    #include<stdio.h>
    
    int main()
    {
        int n, times;
        scanf("%d", &n);
        times = 0;
        while(n != 1){
            if(n%2 == 0){
                n = n/2;
            }else{
                n = 3*n+1;
            }
            times++;
        }
        printf("%d", times);
        return 0;   
    }
    
    1. while循环的格式为:while(条件) 循环体;
    2. 当需要统计某种事物个数时,可以用一个变量来充当计数器。
    3. 不要忘记测试,一个看上去正确的程序可能隐含错误。
    4. 在观察无法找出错误时,可以用“输出中间结果”的方法查错。
    5. 在32位的系统中,运算器一次最多可以处理32位的数据,寄存器的最大宽度也是32位的。然后, C语言中对数据宽度的规定是指针变量、long型变量的宽度推荐是处理器一次能够处理的最大宽度,所以就是32位,也就是4个字节。同理,在64位系统中,运算器、寄存器等一次处理的宽度是64位,也就是8个字节,所以指针变量、long型变量等也就都是8个字节了。
  2. 近似计算
    计算Π/4=1-1/3+1/5-1/7+...,直到最后一项小于10的负6次方。
    #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 = sum+term;
            }else{
                sum = sum-term;
            }
            if(term < 1e-6){
                break;
            }
        }
        printf("%.6f", sum);
        return 0;   
    }
    
    do-while语句不常使用。

循环的代价

  1. 阶乘之和
    输入n,计算S=1!+2!+3!+...+n!的末6位(不含前导0)。n<=10的6次方。

    #include<stdio.h>
    
    int main()
    {
        int n;
        scanf("%d", &n);
        int six = 0;
        for(int i = 1; i<=n; i++){
            int s = 1;
            for(int j =1; j<=i; j++){
                s = s*j;
            }
            six += s;
        }
        printf("%d", six%1000000);
        return 0;   
    } 
    

    用上面的程序会发现两个问题:
    - 输入100时,会出现负数,乘法溢出了。
    - 输入10的6次方,也会溢出,同时发现太慢了。

    从题目可以知道,他只要最后面的六位,可以在中间结果上每次都取模。

    #include<stdio.h>
    
    int main()
    {
        const int MOD = 1000000;
        int n;
        scanf("%d", &n);
        int six = 0;
        for(int i = 1; i<=n; i++){
            int s = 1;
            for(int j =1; j<=i; j++){
                s = (s*j)%MOD;
            }
            six = (six+s)%MOD;
        }
        printf("%d", six);
        return 0;   
    } 
    

    测试几组数据,发现从40开始,答案始终不变,原因是25!的末尾有6个0,所以从第25项开始,后面所有项都不会影响末尾的6位数字,所以可以放弃使用每次都%一下的方法,只需if(n>25 n=25;)

算法竞赛中的输入输出框架

  1. 数据统计
    输入一些整数,求出它们的最小值、最大值和平均值(保留3位小数)。输入保证这些数都是不超过1000的整数。
    #include<stdio.h>
    
    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)x/n);
        return 0;   
    }
    
    上面的程序,如何停止输入呢?
    • windows中,输入完毕后按Enter键,再按ctrl+z键,最后再按Enter
    • Linux中,输入完毕后按Ctrl+D键即可结束输入
    #include<stdio.h>
    #define INF 1000000000
    
    int main()
    {
        int x, n=0, s = 0, kase=0;
        while(scanf("%d", &n) == 1 && n){
            int s = 0, min=INF, max=-INF;
            for(int i = 0; i<n; i++){
                scanf("%d", &x);
                s += x;
                if(x < min){
                    min = x;
                } 
                if(x > max){
                    max = x;
                }
            }
            if(kase) printf("\n");
            printf("case %d: %d %d %.3f\n", ++kase, min, max, (double)s/n);
        } 
        return 0;   
    }
    

练习

  1. 水仙花数
    输出100-999中的所有水仙花数。若3位数ABC满足ABC= A3 + B3 + C3,则称其为水仙花数。例如153=13+53+33,所以153是水仙花数。
    #include<stdio.h>
    #include<math.h>
    
    int main()
    {
        int daffodil;
        for(int i=100; i<=999; i++){
            int unit = i%10;
            int tens = i/10%10;
            int hundreds = i/100;
            bool j = (i == (int)(pow(unit, 3)+pow(tens, 3)+pow(hundreds, 3)));
            if(j){
                printf("%d = %d^3 + %d^3 + %d^3\n", i, hundreds, tens, unit);
            }
        }
    
        return 0;   
    }
    
    这道题没有难度,主要就是熟悉熟悉循环的运用。
  2. 韩信点兵
    #include<stdio.h>
    
    int main()
    {
    
        while(true){
            int a, b, c;
            scanf("%d%d%d", &a, &b, &c);
            bool isExist = false;
            int i=0;
            for(i = 10; i<=100; i++){
                if(i%3 == a && i%5 == b && i%7 == c){
                    isExist = true;
                    break;
                }
            }
            if(isExist){
                printf("case: %d\n", i);
            }else{
                printf("case: No answer\n");
            }
        }
    
        return 0;
    }
    
    这道题目说“每次只看排尾”,意思也就是只看余数,这样遍历,一次一次试就可以了,虽然效率不高。
  3. 倒三角形
    #include<stdio.h>
    
    int main()
    {
        int n;
        scanf("%d", &n);
        for(int i=1; i<=n; i++){
            // 输出前面的空格 
            for(int j=1; j<i; j++){
                printf(" ");
            }
            // 输出中间的* 
            for(int k=1; k<=1+2*(n-i); k++){
                printf("*");
            }
            // 输出后面的空格 
            for(int j=1; j<i; j++){
                printf(" ");
            }
            printf("\n");
        }
        return 0;
    }
    
  4. 子序列的和
    #include<stdio.h>
    #include<math.h>
    
    int main()
    {
        int n, m;
        int sign =0;
        while(scanf("%d%d", &n, &m) == 2){
            if(n == 0 && m == 0){
                break;
            }
            double result;
            result = 0;
            for(double i=n; i<=m; i++){
                result += 1.0/pow(i,2);
            }
            sign++;
            printf("Case %d: %.5f\n", sign, result);
        }
    
        return 0;
    }
    
    scanf 的返回值为输入值的个数。
  5. 分数化小数
    #include<stdio.h>
    
    int main()
    {
        int sign = 0;
        int a, b, c;
        while(scanf("%d%d%d", &a, &b, &c) != EOF){
            if(a==0 && b==0 && c==0){
                break;
            }
            double d = 1.0*a/b;
            sign++;
            printf("Case %d: %.*f", sign, c, d);
        
        }   
    
        return 0;
        
    }
    
    注意:%.*f
  6. 排列
    #include<stdio.h>
    
    int main()
    {
        for(int i=1; i<=9; i++){
            for(int j=1; j<=9; j++){
                for(int k=1; k<=9; k++){
                    if(i==j || i==k || j==k){
                        continue;
                    }
                    int a = i*100+j*10+k*1;
                    int b = i*200+j*20+k*2;
                    int c = i*300+j*30+k*3;
                    if(a<999 && b<999 && c<999){
                        printf("%d %d %d\n", a, b, c);
                    }
                }
            }
        }
        return 0;
    }  
    
  7. 猜猜下面程序的输出内容,一定要运行一遍。
    #include<stdio.h>
    
    int main()
    {
        float i;
        for(i=0; i != 10; i += 0.1){
            printf("%.1f\n", i);
        }
        return 0;
    }
    
    double和float都不能用==来比较。根据浮点数的存储参考IEEE 754浮点数标准
    0.4 ≈ 二进制0.011 001100110011...
    0.3 ≈ 二进制0.0100110011001100...
    0.7 ≈ 二进制0.1011001100110011...
    但是,float只存前几位,两个float想加只有前几位参与操作,损失后面的精度,如果前面的不一样样比较就出现不想等,如果都一样这里就相等,但你换别的数字试试可能也不相等,原因就是精度损失。
    可以把要比较的两个数相减的绝对值与一个较小的数比,例如,fabs(f1-f2)<1e-6
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 230,247评论 6 543
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 99,520评论 3 429
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 178,362评论 0 383
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 63,805评论 1 317
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 72,541评论 6 412
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 55,896评论 1 328
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 43,887评论 3 447
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 43,062评论 0 290
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 49,608评论 1 336
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 41,356评论 3 358
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 43,555评论 1 374
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 39,077评论 5 364
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 44,769评论 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 35,175评论 0 28
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 36,489评论 1 295
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 52,289评论 3 400
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 48,516评论 2 379

推荐阅读更多精彩内容