第5周 循环(一)北理

第四章 循环结构的程序设计

4.1、需要重复执行的程序
4.2、至少要执行一次的循环
4.3、已知循环次数用for语句
4.4、循环控制–简单的循环应用

  • 什么问题需要循环程序解决
  • 如何表达循环中的条件
  • 如何构造循环控制流程?
  • 典型的循环应用问题有哪些?

循环问题
- 求累加和:
- 找满足条件的数:最大数、最小数
- 分类问题:字符
- 数列问题

经典循环问题:
- 鸡兔同笼问题
- 梅森素数问题
- 有数列2/3、4/5、6/9、10/15……
- 输出n、m中能被3整除,且至少有一个数字是5的所有数。
- 求3-150中所有素数的和
- 有一个八层高的灯塔,每层所点灯数等于上一层的2倍,一共有765盏灯,求塔低灯数

(一)需要重复执行的程序 while()循环
while()循环实现先判断后循环(当型循环)
特点:
在循环入口处判断当条件为真时执行循环。

关系运算符比较的结果为逻辑真(true)或者逻辑假(false)

程序执行的结果为121
a =1;b=2;c=3;
while(a<b<c)
{
    t=a;
    a=b;
    b =t;
    c--;
}
printf("%d %d %d",a,b,c);

例子求平均值
从键盘输入10个整数,求这10个整数的和
(1)这十个数不是连续的累加和(任意数):
(2)有些情况是用累加器求连续的整数和(不是任意的数)

求任意的是个数的和
#include <stdio.h>

int main()
{
    int count = 0;
    int sum = 0;
    int num;

    while (count < 10)
    {
        count++;
        printf("Enter the No.%d =",count);
        scanf("%d",&num);
        sum += num;
    }
    printf("Average=%d\n",sum/10);
    return 0;

}

区别方法一与方法二

for循环求和

#include <stdio.h>

int main()
{
    int sum = 0;
    int count = 10;
    float average = 0;
    int num = 0;

    for (int i = 0; i < count; i++)
    {
        printf("NO.%d--->",i);
        scanf("%d",&num);
        sum += num;
    }
    average = (float)sum / count;
    printf("%f\n",average);
}
没有指定精度的时候,float的精确位数是6
格式说明符正确与否影响结果的正确性

do-while求和

#include <stdio.h>

int main()
{
    int sum = 0;
    float average = 0;
    int i = 0;
    int num = 0;

    while (i < 10)
    {
        scanf("%d",&num);
        sum += num;
        ++i;
    }
    average = (float)sum / 10;
    printf("%lf", average);
}
求的是连续的累加和
#include <stdio.h>
int main()
{
    int n = 1;
    int sum = 0;
    while(n<100)
    {
        sum += n;
        n++;
        printf("%d",sum);
    }

(二)至少要执行一次 do-while

说明
循环体至少要执行一次
**直到条件为假时,退出循

例子:
成绩录入并计算平均分成绩的有效性)

#include <stdio.h>
int main()
{
    int s,b= 1;
    do{
        printf("输入第%d个成绩:",n);
        scanf("%d",&s);
        if(s<0||s>100)
        printf("成绩无效,重新输入!\n");
        else
        {
            printf("录入成功");

执行程序后,i,j, k的值是什么?i=5,j=4,k=6;

#include <stdio.h>

int main()
{
    int a = 10;
    int b = 5;
    int c = 5;
    int d = 5;
    int i, j, k = 0;
    for (; a > b; ++b)
        i++;
    while (a > ++c)
        j++;
    do
    {
        k++;
    } while (a > d++);
    return 0;
}

为什么是死循环啊?while的条件不是不对吗 ?

    x = 3;
    do 
    {
        y = x--;
        if (!y)
        {
            printf("x");
            continue;
        }
        printf("#");
    } while (1 <= x <= 2);
是死循环?

例子:测试录入速度

  • 问题描述:
    从键盘上录入英文文章并显示,记录输入字符的个数,直到输入结束标记时才停止。
  • 问题分析:
    由于不知道要输入的字符数量,只能靠结束标记停止循环
    设:结束标记为字符#
#include <stdio.h>
#include <time.h>

int main()
{
    char ch;
    int n = 0;
    time_t t1, t2;
    time(&t1);//获取时间并存入变量
    while (ch = getchar() != '#')
        n++;
    time(&t2);
    printf("\n总的输入字符数:%d",n);
    printf("\n平录入速度:%.2fs",1.0*n/(t2-t1));
    return 0;

}

> 例子: N的阶乘n!
- 问题描述:输入n ,计算n的阶乘
- 问题分析:n! =1*2*….*(n-1)n

方法一:

#include <stdio.h>

int main()
{
    int n = 0;
    int sum = 1;

    printf("求n的阶乘: ");
    scanf("%d",&n);

    for (int i = 1; i <= n; i++)
    {
        sum *= i;
    }

    printf("%d\n",sum);
}

方法二:n的阶乘n!

问题描述:
输入n,计算N的阶乘
问题分析
n!=1*2…*(n-1)*n

#include <stdio.h>

int main()
{
    int n,t;
    int result = 1;
    scanf("%d",&n);

    t = n;
    if (n > 0)
    {
        do
        {
            result *= n;
            n--;
        } while (n);
    }
    printf("%d! = %d\n",t,result);

}

例子:字符分类统计

问题描述
从键盘上输入任意的字符,按下列规则进行分类计数。
问题分析:
第一类:‘0’‘1’‘2’‘3’‘4’‘5’‘6’‘7’‘8’‘9’
第二类:‘+’‘-’‘*’‘/’‘%’
第三类:其他的字符
当输入字符‘\’时先计数后停止接受输入。

#include <stdio.h>

int main()
{
    int class1 = 0;
    int class2 = 0;
    int class3 = 0;
    char ch;

    do
    {
        ch = getchar();
        switch (ch)
        {
        case '0':case '1':case '2': case '3':
        case '4':case '5':case '6': case '7':
        case '8':case '9':
            class1++;
            break;
        case '+':case '-': case '*': case '/':
            class2++;
            break;
        default:
            class3++;
            break;
        }
    } while (ch != '\\');
        printf("\n class1 = %d,class2 = %d,class3 = %d\n", class1, class2, class3);

        return 0;

}

从直接输入到IDE中得到测试结果,然后有正确的答案,但这样的效果真的好吗?我根本就不理解?所以我给记录下来了

main()
{
    int a = 10;b=5;c=5;d=5;i=0;j=0;k= 0;
    for( ; a>b;)
    i++;
    while(a>++c)
    j++;
    do
    {
        k++;
    }while(a>d++);
}
x= 3;
do{
y = x--;
if(!y)
{
    printf("x");
    continue;
}while(1<=x<=2);

(三)已知循环的次数

求1到n的和?(求和问题)

从键盘输入n,计算1都n的和

#include <stdio.h>

int main()
{
    int n, sum = 0;
    int i = 0;

    printf("Input n:\n");
    scanf("%d",&n);

    for (i = 0; i < n; i++)
    {
        sum += i;
    }
    printf("%d-->%d",i,sum);
    return 0;
}

> 例子:分数数列: 1/2、2/3、3/4….前20项的和。
求分数的和时要考虑到数据类型的选择,不能用int

#include <stdio.h>
int main()
{
    for(i = 1;i<=20;i++)
    {
        sum += i/i+1;
    }
    printf("%d\n",sum);
    return 0;
}

1、为什么要乘以1.0
2、为什么要多加括号

#include <stdio.h>

int main()
{
    double sum = 0;

    for (int i = 1; i <= 3; i++)
    {
        sum += i*1.0 / (i + 1);
    }
    printf("%lf",sum);

    return 0;
}

求和问题
例子:斐波那契数列

斐波那契数列 :1,1,2,3,5,8,13,21,34,55,89,144。。
通项公式:
a1 = 1 a2 =1
an=a(n-1) +a(n-2)(n>=3,n属于正整数N)后一个数是前两个数和
输入n,输入前n项,及前n项的和

#include <stdio.h>

int main()
{
    int n ,t,a1 = 1;
    a2 = 1;s= 0;
    printf("%d %d",a1,a2);
    for(int i = 0;i <n;i++)
    {
        t=a1+a2;
        printf("%d",t);
        s=s+t;
        a1 = a2;
        a2 = t;
    }
    printf("s=%d ",s);
    return 0;
}       
#include <stdio.h>

int main()
{
    int a1, a2 = 1;
    int num = 0;
    int sum = 0;
    int temp = 0;

    printf("输入项数:");
    scanf("%d",&num);
    printf("%d %d",a1,a2);

    for (int i = 3; i <= num; i++)
    {
        temp = a1 + a2;
        printf("%d",temp);
        sum = sum + temp;
        a1 = a2;
        a2 = temp;
    }

    printf("sum=%d  \n", sum);
    return 0;
}

4.4 循环控制 —简单的应用

循环的应用
例子:打印100~200之间所有能被3或7整除的数

#include <stdio.h>

int main()
{
    for (int i = 100; i < 200; i++)
    {
        if (i % 3 == 0 || i % 7 == 0)
            printf("%d\n", i);
    }
    return 0;
}

(2)尝试使用while循环实现:

控制控制的简单应用

水仙花数

  • 问题描述:

打印出所有的水仙花

  • 问题分析:

水仙花数是指一个三位数,它的每个位上的数字的3次幂之和等于它本身。

153 = 1*1*1+5*5*5+3*3*3

问题的关键是如何取得三位数的每个位数

#include <stdio.h>

int main()
{
    int a, b, c;
    for (int i = 100; i < 1000; i++)
    {
        a = i % 10;
        b = i / 10 % 10;
        c = i / 100;

        if (i == a*a*a + b*b*b + c*c*c)
            printf("%d\n", i);
    }
    return 0;
}

打印时出现问题,看似不会出现问题还是出现了问题
把等号==写成了=
最重要的原因是自己竟然没有耐心找出错误,总觉得自己没有错位。

例子:判断素数

输入X,判断x是否为素数:
只能被1和它本身整除的数为素数

#include <stdio.h>

int main()
{
    int a1, a2 = 1;
    int num = 0;
    int sum = 0;
    int temp = 0;

    printf("输入项数:");
    scanf("%d",&num);
    printf("%d %d",a1,a2);

    for (int i = 3; i <= num; i++)
    {
        temp = a1 + a2;
        printf("%d",temp);
        sum = sum + temp;
        a1 = a2;
        a2 = temp;
    }

    printf("sum=%d  \n", sum);
    return 0;
}

例子:大数分解

从键盘上输入一个大于1的整数,通过算法将该整数分解为若干质数因子的乘积
a=a/i 找到下一个因子之后获得的新a
(1)任何一个大数都可以分解为若干个素数的乘积
(2)什么是因子:能被整除的数都是
(3)什么是素数
(4)凡是能被这个数整除的数都是这个数的因子
(5)这个数就是这些因子的乘积
被除数能被除数整除

#include <stdio.h>

int main()
{
    int a, i;
    scanf("%d",&a);

    for (i = 2; a != 1;)
    {
        if (a%i == 0)
        {
            a = a / i;
            printf("%d ", i);
        }
        else
            i++;
    }
}

第六周 循环结构的程序设计
4.5 循环的嵌套
4.6 break和continue;
4.7 需要用循环解决的问题的讨论

4.5 循环的嵌套(一)循环的嵌套—构成平面图案

打印九九乘法表

#include <stdio.h>

int main()
{
    int  j, i;

    for (int i = 1; i <= 9; i++)
    {
        printf("\t第%d列 ", i);
    }
    printf("\n");

    for (i = 1; i <= 9; i++)
    {
        printf("第%d行", i);
        for (j = 1; j <= 9; j++)
        {
            printf(" %2d*%d=%d ", i, j, i*j);
        }
        printf("\n");
    }
    return 0;
}
内循环的终值与外循环的循环控制变量有关系

打印三角图案

打印的内部是实心的

#include <stdio.h>

int main()
{
    int i, j, n = 0;
    printf("需要打印多少行: ");
    scanf("%d",&n);

    for (i = 1; i <= n; i++)
    {
        for (j = 1; j <= n - i; j++)
        {
            printf(" ");
        }
        for (j = 1; j <= 2 * i - 1; j++)
        {
            printf("*");
        }
        printf("\n");
    }
    return 0;
}

例子:打印三角图案
打印的内补是空的只有边

#include <stdio.h>

int main()
{
    int i, j, n;
    printf("需要打印的行数:");
    scanf("%d",&n);

    for (i = 1; i <= n; i++)
    {
        for (j = 1; j <= n - i; j++)
        {
            printf(" ");
        }
        printf("*");
        for (j = 1; j <= 2 * i - 3;j++);
        {
            printf(" ");
        }
        if(i!=1)//逆向思维
            printf("*");
        printf("\n");
    }
    return 0;
}
#include <stdio.h>

int main()
{
    int i, j;
    float s;
    for (i = 6; i > 4; i--)
    {
        s = 0.0;
        for (j = i; j > 3; j--)
            s = s + i*j;
    }
    printf("%f\n",s);
    return 0;
}

break语句和continue语句
break的功能
在switch语句中结束case子句在控制转到switch语句之外
在循环体中使用,结束当前的循环过程,使控制转移到循环语句之外的下一条语句。
break再讨论
break在循环体中的作用是:中断当前所在的这一级循环的循环

break再讨论;
找出最大的素数
输入n,输出1到n之间的最大的素数

问题分析:
n =1,2,3,4,5,6,7,8,9,数据域
i =1,2,3,4,5,6,7,
两处需要中断:
1、外循环时找到了
2、内循环中当前数废除了

continue的用法

continue的功能
- continue语句仅能在循环语句中使用。
- 作用是仅跳过当前这一次循环
- 对于for语句将控制转到执行增量和条件测试部分
- 对于while和do-while语句,将控制转到条件测试部分

循环中断与循环继续

例子:输入10个整数,统计其中的正数的个数及平均值。

循环的综合应用-数的排列组合问题

鸡兔同笼

#include <stdio.h>

int main()
{
    int x, y;
    int n = 0;
    for (x=1;x<35;x++)
    {
        for (y=1;y<35;y++)
        {
            if (((x + y) == 35) && ((2 * x + 4 * y) == 94))
            printf("鸡:%d 兔:%d\n",x,y);

            n++;
        }
    }
    printf("n=%d\n",n);
    return 0;
}

例子:取出1~9中的4个互不相同的数 ,使他们的和为12,用穷举法输出所有满足条件的4个数的排列

讨论:
(1)注意到:互不相同的4个数均小于或等于6.
(2)把所有的判断均放在最内层循环不合理,应放到与之相关的循环中,i==j的判断,只有和i、j有关,放在j循环中只判断9*9=81次,而放在最内存中判断9*9*9*9=6561次
(3)因为i,j,k和I的和为12,所以所有的I=12-i-j-k,这样就减少一重循环。不过,要注意I>0且I<7,因为i+j+k最少是1、2、3的组合,即6.

分析:若i,j,k,I分别代表4个数,列出它们所有的排列,从中找出符合条件的i,j,K和I(i+j+k+i=12,且这四个数互不相同)

#include <stdio.h>
int main()
{
    int i, j, k, l, n = 0,m=0;
    for (i = 1; i < 10; i++)
    {
        for (j = 1; j < 10; j++)
        {
            for (k = 1; k < 10; k++)
            {
                for (l = 1; l < 10; l++)
                {
                    m++;
                    if (i == j || i == k || i == 1 || j == k || j == 1 || k == 1)
                        continue;
                    if (i + j + k + l != 12)
                        continue;
                    printf("{%d,%d,%d,%d}",i,j,k,l);
                    if (n % 5 == 0)
                        printf("\n");
                }
                printf("\n\n%d,%d\n", n, m);
                return 0;
            }
        }
    }
}

优化之后的程序是:

#include <stdio.h>

int main()
{
    int i, j, k, l, n = 0, m = 0;
    for (i = 1; i < 7; i++)
    {
        for (j = 1; j < 7; j++)
        {
            if (i == j)
                continue;
            for (k = 1; k < 7; k++)
            {
                m++;
                l = 12 - i - j - k;
                if (i == k || j == k || l == i || l == j || l == k)
                    continue;
                if (l <= 0 || l > 7)
                    continue;
                n++;
                printf("{%d,%d,%d,%d}",i,j,k,l);
                if (n % 5 == 0)
                    printf("\n");
            }
        }
    }
    printf("\n\n%d,%d",n,m);
}

求555555的约数中最大的三位数是多少?

思路:从?最大的约束开始找,找到为止。

#include <stdio.h>

int main()
{
    int j;
    long n;
    printf("please input number: ");
    scanf("%ld",&n);

    for (j = 999; j >= 100; j--)
    {
        if (n%j == 0)//若能够整除j,则j就是约数
        {
            printf("3digits in %ld = %d\n",n,j);
            break;//控制退出循环
        }
        return 0;
    }
}

求14的13次方数的最后三位数

设计求x的y次方末尾三位数的逼

#include <stdio.h>

int main()
{
    int i = 1;
    int x, y;
    int a = 1;

    printf("Input X and Y: ");
    scanf("%d%d", &x, &y);

    while (i < y)
    {
        a = a*x % 1000;
        i++;
    }
    printf("3 digits is: ");
    printf("%d\n",a%1000);
}

打印空心图案

输入n值,输出如图所示图形
Z
Y X
W V
U T
S R
Q P
O N
M L
K
n=5

#include <stdio.h>

int main()
{
    char c = 'Z';
    int i, j, n;
    printf("\nPlease Enter n:");
    scanf("%d",&n);
    for (i = 1; i <= n; i++)//控制输出的行数
    {//打印最后一个字符之前的空格和字符
        for (j = 1; j <= n + i - 2; j++)
            if (j == n - i + 1)
                printf("%c", c--);
            else
                printf(" ");
        printf("%c\n",c--);
    }
    for (i = 1; i < n; i++)
    {
        for (j = 1; j < 2 * (n - 1) - i; j++)
            if (j == i + 1)
                printf("%c", c--);
            else
                printf(" ");
        printf("%c\n",c--);
    }
}
如果打印的图案中出现问号,那么是未显示的字符(键盘上敲不进去的字符)
i <= n
打印n行的话,就应该包含n的,不应该把等于n给忽略掉。
if (j == n - i + 1)
总是把测试等与数学里面的等号混淆
if (j == i + 1)
总是把测试等与数学里面的等号混淆
j <= 2 * (n - 1) - i
内循环的终值总是和外循环的控制变量有关系
j <= n + i - 2
内循环的终值总是和外循环的控制变量有关系

打印图形
以下图形用什么算法实现程序最简单?你会考虑哪些测试用例来保证程序的正确性和坚固性?请给出你的实现程序。(图中n=5)

打印空心图形
输入n值,输出如图所示边长为n的空心正六边型(n=5)。
程序如下,但这个程序运行结果不正确,你可以修改吗?

#include<stdio.h>
 int  main( )
 { int i, j, n;
   printf("\nPlease Enter n:");
   scanf ("%d", &n);
   for(i=1;i<=n;i++)                 
   {  for(j=1;j<=2*n-i;j++)
         if(j==n-i+1 || j>n-i+1 && i==1)
            printf("*");
         else  printf(" "); 
   }
   for(i=1;i<n;i++)              
   {  for(j=1;j<=3*(n-1)-i;j++)
         if(j==i+1 || j>i+1 && i==n-1)
            printf("*");
         else  printf(" ");
      printf("*\n");
   }
}
来自课件“讨论题3

已知2014年1月1日是星期三,你可以编写程序在屏幕上输出2015年的年历吗?
提示:关于闰年的计算方法是,如果某年的年号能被400除尽, 或能被4除尽但不能被100除尽,则这一年就是闰年。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值