循环语句来了!

文章介绍了编程中实现重复执行操作的方法,包括for、while和do-while循环的使用,以及break和continue语句的控制。此外,还讲解了如何判断素数、计算Fibonacci数列和进行进制转换等算法问题。
摘要由CSDN通过智能技术生成

重复 n 次

如何实现执行某种操作若干次呢?可以设定一个整数 i,结合判断条件实现
给 i 赋一个初值
设定循环结束时 i 的终值或终止条件
每次循环后,i 的值如何变化
本质上就是产生一个序列,序列个数就是循环次数

(1)重复 10000 次输出 a

第 1 部分:设定 i = 1;(只执行 1 次)
第 2 部分:当 i <= 10000; 时,继续执行循环;当 i > 10000 时,退出循环;
第 3 部分:每次循环后,++i;
C 语言中的 for 循环语法:

for (第 1 部分; 第 2 部分; 第 3 部分) { 代码 }

注意:小括号中有且只有 2 个分号!!!
#include<stdio.h>//连续输出 10000 个 aintmain(){
    for (int i = 1; i <= 10000; ++i)
        printf("a");
    return0;
}
#include<iostream>intmain(){
    for (int i = 1; i <= 10000; ++i)
        std::cout << 'a';
    return0;
}

(2)重复 n 次输出 a,并要求每个 a 前面带上序号,逐行输出

#include<iostream>//连续输出 n 个 aintmain(){
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i)
        printf("%d: a\n", i);
    return0;
}
#include<iostream>usingnamespacestd;
intmain(){
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cout << i << ": " << "a\n";
    return0;
}

做数列的计算

(1)从 1 加到 10000 的和

第 1 部分:设定 i = 1;(只执行 1 次)
第 2 部分:当 i <= 10000 时,继续执行循环;
第 3 部分:++i;

练习:计算总分

//需要将 1 到 10000 的数字依次与 sum 相加#include<iostream>//连续输出 10000 个 aintmain(){
    int sum = 0;
    for (int i = 1; i <= 10000; ++i)
        sum += i;
    printf("%d", sum);
    return0;
}

while 循环

for循环中的第1部分
while (for循环中的第2部分) {
    ...
   for循环的第3部分
}

还是以求 1 到 10000 的数字之和为例:

#include<stdio.h>intmain(){
    int sum = 0, i = 1;
    while (i <= 10000) {
        sum += i;
        ++i;
    }
    printf("%d", sum);
    return0;
}

do-while 循环

for循环第1部分
do {
    ...
   for 循环第3部分
} while (for循环的第2部分);

从代码可以看出,它第一次执行循环体语句前,并没有执行第2部分的判断,而是在第一次循环以后,从第二次循环起,才每次先判断再执行。

for 和 while 循环最少可能执行 0 次,而 do-while 循环至少要执行 1 次。

#include<stdio.h>intmain(){
    int sum = 0, i = 1;
    do {
        sum += i;
        ++i;
    } while (i <= 10000);
    printf("%d", sum);
    return0;
}

break 语句

任何时候,在函数体内都可以使用 break; 直接退出循环(注意只能退出一层)。

continue 语句

使用 continue; 语句可以直接跳过当前循环体内位于 continue; 后面的所有语句,直接执行for循环的第3部分,进入下一次循环。

#include<stdio.h>//输入n个数,求其中奇数的和intmain(){
    int n, i = 1, x, sum = 0;
    scanf("%d", &n);
    for (i = 1; i <= n; ++i) {
        scanf("%d", &x);
        //若x为偶数,则跳过后面的语句,直接去执行++i;输入下一个xif (x%2 == 0) continue;
        sum += x;
    }
    printf("%d", sum);
    return0;
}

处理数列的前后关系

练习:连续上升数列

需要处理一个数列的每个数与其前后的数之间的关系时,通常我们需要用到一个辅助的临时变量,我们起名叫 last。
这时我们可能会用一个特殊的输入方式:将第一个数和 n 在同一个 scanf 中先输入,并将其赋值给 last。
break:跟在 switch 语句中遇到的一样,此时用 break 可以 直接退出循环
循环外如何判断是 break 退出:i <= n;//与 for 循环中的条件一致
#include<iostream>intmain(){
    int i, n, x, last;
    scanf("%d%d", &n, &last);
    for (i = 2; i <= n; ++i) {
        scanf("%d", &x);
        //如果发现非递增,就退出循环,此时 i <= nif (x <= last) break;
        last = x;
    }
    if (i <= n) puts("NO");
    elseputs("YES");
    return0;       
}
  • 三目运算符

#include<iostream>intmain(){
    int i, n, x, last;
    scanf("%d%d", &n, &last);
    for (i = 2; i <= n; ++i) {
        scanf("%d", &x);
        //如果发现非递增,就退出循环,此时 i <= nif (x <= last) break;
        last = x;
    }
    i <= n ? puts("NO") : puts("YES");
    return0;       
}

练习:病毒检测

#include<iostream>intmain(){
    int i, n, last = -1, x, cnt;
    scanf("%d", &n);
    for (i = 1; i <= n; ++i) {
        scanf("%d", &x);
        if (x%30 == 0) {
            if (x>last && last%30==0) ++cnt;
            else cnt = 1;
        }
        if (cnt == 5) break;
        last = x;
    }
    if (cnt == 5) printf("Yes\n%d", i-4);
    elseputs("No");
    return0;
}
上面代码的 for 循环中,其实 x%30 如果不为 0,后面的嵌套显得有些累赘,能否让代码更简洁呢?可以,需要引入循环的另一个关键字——continue
continue——停止当前这次循环,直接去执行 ++i, 跳入下一次循环
#include<iostream>intmain(){
    int n, i, x, last = -1, cnt = 0;
    scanf("%d", &n);
    for (i = 1; i <= n; ++i, last = x) {
        scanf("%d", &x);
        if (x % 30) { cnt = 0; continue; }
        cnt && x>last ? ++cnt : (cnt=1);
        if (cnt == 5) break;
    }
    if (cnt < 5) puts("No");
    elseprintf("Yes\n%d", i-4);
    return0;       
}

循环输入问题

我们经常会遇到一些题目的输入是不给定输入数据个数的,这时候,可以使用以下两种方式来解决:

(1)使用 cin 语句

while (cin >> x)...

这种写法很简单,但是当输入数据达到 10 万左右时,输入时间过慢会导致超时。

(2)使用 scanf 语句

scanf 语句正常读入数据后,会返回本次读入的数据个数,例如:scanf("%d", &x); 成功读入一个整数 x 时,会返回 1;scanf("%d%d", &n, &m); 成功读入 n,m 时会返回 2;而如果读入内容为空导致失败,则会返回 EOF。

由于 OJ(Online Judge在线判题)网站使用测试数据文件自动判题,因此我们的代码实际上都是读入各个文件里的数据,当文件读完时,最后会读到文件结束符—— EOF,即 End Of File,这个符号对应整数 -1,所以,我们可以有如下 3 种写法:

第一种:

与 EOF 判断

while (scanf("%d", &x) != EOF) ...

第二种:

直接与 -1 判断

while (scanf("%d", &x) != -1) ...

第三种:

由于二进制 -1 的各个位均为 1,所以将其按位取反得到 0。

while (~scanf("%d", &x)) ...

最值问题

循环中的最值问题,需要初始化 max 以及 min 变量:
max 需要初始化为可能的最 值,if (x > max) max = x;
min 需要初始化为可能的最 值,if (x < min) min = x;

练习:“讨厌”的最值问题

#include<iostream>intmain(){
    int n, max = 0, min = 10000;
    scanf("%d", &n);
    // i + j + k == n, i > j > kfor (int i = n-3; i > 0; --i)
        for (int j = i-1; j > 0; --j) {
            int k = n - i - j;
            if (k>0 && k<j) {
                if (i < min) min = i;
                if (k > max) max = k;
            }
        }
    max == 0 ? puts("-1 -1") : printf("%d %d", min, max);
    return0;       
}

数位运算

这类题目通常需要使用模运算,例如:取一个数的个位,就将这个数 %10 即可。

练习:数字滑滑梯2

#include<iostream>intmain(){
    int n, h = 1;
    scanf("%d", &n);
    for (int i = n/10; i; i /= 10) h *= 10;
    int m = n;
    do {
        n = n%10*h + n/10;
        printf("%d ", n);
    } while (n != m);
    return0;
}
之所以使用 do{} while(); 的形式,是因为一开始 n!=m 就是不成立的,如果先判断 while(n != m),循环就会直接退出了。
while (for循环第2部分) {}
本题也可以对位数进行循环。
#include<iostream>intmain(){
    int n, h = 1, w = 1;
    scanf("%d", &n);
    for (int i = n/10; i; i /= 10) h *= 10, ++w;
    while (w--) {
        n = n%10*h + n/10;
        printf("%d ", n);
    }
    return0;
}

打印图形

练习:三角形

#include<iostream>intmain(){
    int n;
    scanf("%d", &n);
    //两层for循环,外层对行进行循环,内层对列进行循环for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= i; ++j)
            putchar('*');//每次打印一个字符 put characterputs("");//直接换行 put string
    }
    return0;
}

素数

如何判断一个数是素数?——试除
如果一个大于 1 的正整数 n,从 2 开始,到 \sqrt{n} n 结束,都不能整除 n,则 n 是素数。

证明:

假设 n=a\cdot bn=ab,其中 a,ba,b 为小于 nn 的正整数,且 a<=ba<=b

则有 n=a\cdot b\ge a\cdot a=a^2n=abaa=a2,即 a\le \sqrt{n}an

因此,若 nn 不是素数,它一定有一个小于等于 \sqrt{n}n 的因子。

练习:判断素数

#include<iostream>intmain(){
    int n, i;
    scanf("%d", &n);
    for (i = 2; i*i <= n; ++i) 
        if (n%i == 0) break;
    if (n<2 || i*i<=n) puts("NO");
    elseputs("YES");
    return0;
}
可以对代码进行优化,虽然变长了,但速度更快了。
#include<iostream>intmain(){
    int n;
    scanf("%d", &n);
    //小于2的正整数,或者大于 2 的偶数,都不是素数if (n<2 || n>2 && n%2==0) { puts("NO"); return0; }
    for (int i = 3; i*i <= n; i += 2)
        if (n%i == 0) { puts("NO"); return0; }
    puts("YES");
    return0;
}

特殊数列

迭代法求数列元素
  • Fibonacci 数列

练习:Fibonacci 数列

#include<iostream>//全局变量默认初值为 0constint M = 10007;
intmain(){
    //局部变量,默认初值不定int n, a, b, c;
    a = b = 1;
    scanf("%d", &n);
    //当 n 为 1或2 时,进行特判if (n==1 || n==2) { printf("1"); return0; }
    for (int i = 3; i <= n; ++i)
        c = (a+b)%M, a = b, b = c;
    printf("%d", c);
    return0;
}
有时候,我们完全可以通过 赋初值来省略一些特判。
//利用变量 c 的初值可以做优化#include<iostream>constint M = 10007;
intmain(){
    int n, a = 1, b = 1, c = 1;
    scanf("%d", &n);
    for (int i = 3; i <= n; ++i)
        c = (a + b) % M, a = b, b = c;
    printf("%d", c);
    return0;
}

枚举

练习:回文数

2 种思路:
(1)从 1000 ~ 10000 逐个判断,循环 9000 次,执行 36000 次模运算,较为耗时
(2)当成 4 个数来看,ijji,1\le i \le 9, 0\le j \le 9 ijji,1≤ i≤9,0≤ j≤9,执行 90 次,直接打出结果,效率高
#include<iostream>intmain(){
    for(int i = 1000;i < 10000; ++i)
        if(i/1000==i%10 && i/100%10==i/10%10)
            printf("%d\n", i);
    return0;
}
#include<iostream>intmain(){
    for (int i = 1; i <= 9; ++i)
        for (int j = 0; j <= 9; ++j)
            printf("%d%d%d%d\n", i, j, j, i);
    return0;       
}

<font color=red>使用define宏定义for循环</font>

#include<iostream>#define loop(i, s, t) for(int i = s; i <= t; ++i)intmain(){
    loop(i, 1, 9) loop(j, 0, 9)
        printf("%d%d%d%d\n", i, j, j, i);
    return0;       
}

最大公约数 GCDGCD 和最小公倍数 LCMLCM

辗转相除法(欧几里得定理)
定理1:gcd(a,b)=gcd(b,a\%b) gcd( a, b)= gcd( b, a% b)
定理2:gcd(a,0)=a gcd( a,0)= a

练习:分苹果

#include<iostream>intmain(){
    int a, b, t, n, m;
    scanf("%d%d", &n, &m);
    a = n, b = m;
    while (b) t = a, a = b, b = t % b;
    printf("%d", n * m / a);
    return0;       
}

进制转换

练习:进制转换

#include<iostream>typedeflonglong LL;
intmain(){
    int n, r;
    LL ans = 0, b = 1;
    scanf("%d%d", &n, &r);
    while (n)
        ans += n % r * b, b *= 10, n /= r;
    printf("%lld", ans);
    return0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值