100个经典C程序:11-20

根据互联网上流程的经典C程序例子整理,调整了格式,补充了问题的分析,代码也进行了调试和修改,非常适合初学者学习。本文是第11-20个C程序。

(备注:整理的时候发现有些例子价值不大,就直接删掉了。有些例子原始的代码比较差进行了重写;还有一些例子原始代码尚可但有更好的解法,所以保留原版本的同时增加了第二个版本的程序。)

前文链接:100个经典C程序:01-10

011:猴子摘桃

题目:
一只猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个;第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃了前一天剩下的一半加一个。到第N天早上想再吃时,见只剩下一个桃子了。问:第一天共摘了多少个桃子?


程序分析:第N天剩余一个,则从第N-1天开始倒推即可,一直推到第1天。第x-1天桃子数量是 (x天数量+1),所以从第N天的一个倒推就可以。


程序源代码:

#include<stdio.h>
int main(){
	int n,i,sum=0,num=1;
	// 输入天数
	scanf("%d",&n);
	for(i=n-1;i>=1;i--){
	  sum=(num+1)*2;
	  num=sum;
	}
	printf("%d",sum);
	return 0;
}

012:牛顿迭代法求平方根

利用牛顿迭代法求一个数的平方根。


牛顿迭代法是大名鼎鼎的牛顿提出的求方程近似解的方法,具体来说对 [ a , b ] [a, b] [a,b]上连续且单调的函数 f ( x ) f(x) f(x),求方程 f ( x ) = 0 f(x)=0 f(x)=0 的近似解。

牛顿迭代法的原理这里不再赘述,有兴趣的朋友可以自行搜索,这里只讲针对求平方根的情况。对于求n的平方根,按照牛顿迭代法可以得到一个迭代公式:
x i + 1 = x i + n x i 2 x_{i+1} = \frac{x_i+\frac{n}{x_i}}{2} xi+1=2xi+xin
这个迭代公式每一次迭代 x i + 1 x_{i+1} xi+1都比 x i x_i xi更接近 n \sqrt{n} n 。利用这个迭代公式,选定一个初始的近似解,不断迭代,知道精度达到要求即可。判断精度是否达到要求也很简单,只需要计算 x i x_{i} xi x i + 1 x_{i+1} xi+1的差值是否低于预设精度即可。


程序源代码:

#include<math.h>

const float Epsilon = 1.0E-9; /*控制解的精度*/
int main()
{
    float a,x0,x1;
    printf("请输入要求平方根的数:");
    scanf("%f",&a);
    /* x0是初值,这里选取的是输入值的二分之一,很合理。当然还有更好的办法,不过作为一个简单的练习程序来说使用二分之一足够了。*/
    x0=a/2;
    x1=(x0+a/x0)/2;
    while(fabs(x1-x0)>=Epsilon)
    {
        x0=x1;
        x1=(x0+a/x0)/2;
    }
    printf("%f的平方根:%f\n",a, x1);
    return 0;
}

另一种算法:

#include<math.h>

const float Epsilon = 1.0E-6; /*控制解的精度*/
int main()
{
    float a,x0,x1;
    do
    {
        printf("请输入要求平方根的数,必须大于0:");
        scanf("%f",&a);
    }
    while(a <= 0);
    /* x0是初值,这里选取的是输入值的二分之一。当然还有更好的办法,不过作为一个简单的练习程序来说使用二分之一足够了。*/
    x1=a/2;
    do
    {
        x0=x1;
        x1=(x0+a/x0)/2;
    }
    while(fabs(x1-x0)>=Epsilon);
    printf("%f的平方根:%f\n",a, x1);
    return 0;
}

013:牛顿迭代法求方程根

题目: 用牛顿迭代法 求方程 2 x 3 − 4 x 2 + 3 x − 6 2x^3-4x^2+3x-6 2x34x2+3x6 的根。


牛顿迭代法的公式:
x i + 1 = x i − f ( x ) f ′ ( x ) x_{i+1} = x_i - \frac{f(x)}{f^{\prime}(x)} xi+1=xif(x)f(x)
而:
f ′ ( x ) = 6 x 2 + 8 x + 3 f^{\prime}(x) = 6x^2 + 8x + 3 f(x)=6x2+8x+3
所以:
x i + 1 = x i − 2 x 3 − 4 x 2 + 3 x − 6 6 x 2 + 8 x + 3 x_{i+1} = x_i - \frac{2x^3-4x^2+3x-6}{6x^2 + 8x + 3} xi+1=xi6x2+8x+32x34x2+3x6


/* 牛顿迭代法 */

#include<math.h>

const float Epsilon = 1.0E-6; /*控制解的精度*/

int main()
{
    float x1,x0=1.5;
    x1=x0-(2*x0*x0*x0-4*x0*x0+3*x0-6)/(6*x0*x0-8*x0+3);
    while(fabs(x1-x0)>=Epsilon)
    {
        x0=x1;
        x1=x0-(2*x0*x0*x0-4*x0*x0+3*x0-6)/(6*x0*x0-8*x0+3);
    }
    printf("方程的根为%f\n",x1);
    return 0;
}

014:打印菱形

题目:打印出如下图案(菱形)

   *
  ***
 *****
*******
 *****
  ***
   *

程序分析:先说比较容易的方法,把图形分成两部分来看待,前四行一个规律,后三行一个规律,利用双重for循环,第一层控制行,第二层控制列。这个方法比较笨拙,但确实可以完成题目要求,下面第一个程序是这个方法的实现。

再考虑一种更优雅的方法。仔细观察菱形,可以把它当做空格和星号组成的正方形,尺寸就是行数n(本题中是7)。每一行可以看成a个空格,加上b个星号,再加上a个空格,且a+b+a=行数n。所以,每一行我们可以先计算星号数量b,然后用(n-b)/2得出a,这样每一行的输出逻辑就是:连续输出a个空格,再连续输出b个星号,之后再输出一个换行。每一行的星号数量b也很有规律,当b小于等于行号n时,每行比上一回加2;当b大于n时,每行比上一行减2。下面第二个程序是这种方法的实现。


程序源代码:

#include <stdio.h>

int main()
{
    int i,j,k;
    for(i=0; i<=3; i++)
    {
        for(j=0; j<=2-i; j++)
            printf(" ");
        for(k=0; k<=2*i; k++)
            printf("*");
        printf("\n");
    }
    for(i=0; i<=2; i++)
    {
        for(j=0; j<=i; j++)
            printf(" ");
        for(k=0; k<=4-2*i; k++)
            printf("*");
        printf("\n");
    }
}

版本二(修改line_count大小就可以得到不同大小的菱形):

#include <stdio.h>

int main()
{
    int line_count = 7;
    for (int i = 0; i < line_count; i ++) {
        int star_count = 1 + 2* i;
        if (star_count > line_count) {
            star_count = line_count - (star_count - line_count);
        }
        int space_count = (line_count - star_count) / 2;
        while(space_count --) printf(" ");
        while(star_count --) printf("*");
        printf("\n");
    }
    return 0;
}

015:判断回文数

题目:一个5位数,判断它是不是回文数。即12321是回文数,个位与万位相同,十位与千位相同。


程序分析:由于题目给出了5位数的限制条件,所以比较简单粗暴的方法就是依次拆解每一位数,然后对比第一位和第五位以及第二位和第四位。这个方法的程序非常简单,就不再列出了。

一个更通用的方法是,通过取余依次获取输入数字的每一位,然后反向组合起来,和原始数字做对比,一致的才是回文数。下面列出了这种思路的程序。


程序源代码:

#include <stdio.h>
 
int main()
{
    int n, reversedInteger = 0, remainder, originalInteger;
 
    printf("输入一个整数: ");
    scanf("%d", &n);
 
    originalInteger = n;
 
    // 翻转
    while( n!=0 )
    {
        remainder = n%10;
        reversedInteger = reversedInteger*10 + remainder;
        n /= 10;
    }
 
    // 判断
    if (originalInteger == reversedInteger)
        printf("%d 是回文数。", originalInteger);
    else
        printf("%d 不是回文数。", originalInteger);
    
    return 0;
}

备注:这个程序更通用,可以判断更多位数的回文数。但对于极端情况,是有可能出现溢出整型上界的情况的。

016:判断星期几(switch语句练习)

题目:请输入星期几的第一个字母来判断一下是星期几,如果第一个字母一样,则继续判断第二个字母。


程序分析:用switch语句比较好,如果第一个字母一样,则判断用情况语句或if语句判断第二个字母。


程序源代码:

#include <stdio.h>

int main()
{
    char letter;
    printf("please input the first letter of someday\n");
    while ((letter=getch())!='Y') /*当所按字母为Y时才结束*/
    {
        switch (letter)
        {
        case 'S':
            printf("please input second letter\n");
            if((letter=getch())=='a')
                printf("saturday\n");
            else if ((letter=getch())=='u')
                printf("sunday\n");
            else printf("data error\n");
            break;
        case 'F':
            printf("friday\n");
            break;
        case 'M':
            printf("monday\n");
            break;
        case 'T':
            printf("please input second letter\n");
            if((letter=getch())=='u')
                printf("tuesday\n");
            else if ((letter=getch())=='h')
                printf("thursday\n");
            else printf("data error\n");
            break;
        case 'W':
            printf("wednesday\n");
            break;
        default:
            printf("data error\n");
        }
    }
}

017:求100以内的素数

题目:求100之内的素数


程序分析:例子002已经给出了一个暴力检验的程序,这里改用筛数法计算。


程序源代码:

#include<stdio.h>
#include<math.h>

int main()
{
    int n = 100;
    int is_prime[101];
    is_prime[0] = is_prime[1] = 0;
    for (int i = 2; i <= n; ++i) is_prime[i] = 1;
    for (int i = 2; i <= n; ++i)
    {
        if (is_prime[i])
        {
            if (i * i > n) continue;
            for (int j = i * i; j <= n; j += i)
                // 因为从 2 到 i - 1 的倍数我们之前筛过了,这里直接从 i
                // 的倍数开始,提高了运行速度
                is_prime[j] = 0;  // 是 i 的倍数的均不是素数
        }
    }
    int count = 0;
    for (int i = 2; i <= n; ++i)
    {
        if (is_prime[i])
        {
            count ++;
            printf("%6d", i);
            if (count % 5 == 0 ) printf("\n");
        }
    }
    printf("0-%d之间总计%d个素数\n", n, count);
    return 0;
}

018:矩阵对角线求和

题目:求一个3*3矩阵对角线元素之和


程序分析:利用双重for循环控制输入二维数组,再将a累加后输出。


程序源代码:

#include<stdio.h>
#include<math.h>

int main()
{
    float a[3][3],sum=0;
    int i,j;
    printf("please input rectangle element:\n");
    for(i=0; i<3; i++)
        for(j=0; j<3; j++)
            scanf("%f",&a[j]);
    for(i=0; i<3; i++)
        sum=sum+a[i][i];
    printf("对角线求和结果 %6.2f",sum);
    return 0;
}

019:有序数组的插入

题目:有一个已经排好序的数组。现输入一个数,要求按原来的规律将它插入数组中。


程序分析:原版解法思路:首先判断此数是否大于最后一个数,然后再考虑插入中间的数的情况,插入后此元素之后的数,依次后移一个位置。这个解法对应下面第一个程序。

不过这个解法太啰嗦,更简单的方法是直接把要插入的数据放到最后一个位置,然后从后向前判断是否需要交换。一旦不需要交换了退出循环。这个解法对应下面第二个程序。


程序源代码版本一:

#include<stdio.h>
#include<math.h>

int main()
{
    int a[11]= {1,4,6,9,13,16,19,28,40,100};
    int temp1,temp2,number,end,i,j;
    printf("original array is:\n");
    for(i=0; i<10; i++)
        printf("%5d",a[i]);
    printf("\n");
    printf("insert a new number:");
    scanf("%d",&number);
    end=a[9];
    if(number>end)
        a[10]=number;
    else
    {
        for(i=0; i<10; i++)
        {
            if(a[i]>number)
            {
                temp1=a[i];
                a[i]=number;
                for(j=i+1; j<11; j++)
                {
                    temp2=a[j];
                    a[j]=temp1;
                    temp1=temp2;
                }
                break;
            }
        }
    }
    for(i=0; i<11; i++)
        printf("%6d",a[i]);
}

程序源代码版本2:

#include<stdio.h>
#include<math.h>

int main()
{
    int a[11]= {1,4,6,9,13,16,19,28,40,100};
    int temp1,temp2,number,end,i,j;
    printf("original array is:\n");
    for(i=0; i<10; i++)
        printf("%5d",a[i]);
    printf("\n");
    printf("insert a new number:");
    scanf("%d",&number);
    a[10] = number;
    for (i = 10; i >0; i--)
    {
        if(a[i] < a[i-1])
        {
            int temp = a[i];
            a[i]=a[i-1];
            a[i-1] = temp;
        }
        else
        {
            break;
        }
    }
    for(i=0; i<11; i++)
        printf("%6d",a[i]);
    return 0;
}

两段程序只有中间部分不同,可以看出版本2简洁多了。

020:逆序数组

题目:将一个数组逆序,并输出到屏幕。


程序分析:按位置用开头的元素和结尾的元素依次交换,只需要执行到数组的中间位置,数组就完成逆序了。


程序源代码:

#include<stdio.h>
#include<math.h>

#define N 5
int main()
{
    int a[N]= {9,6,5,4,1},i,temp;
    printf("\n original array:\n");
    for(i=0; i<N; i++)
        printf("%4d",a[i]);
    for(i=0; i<N/2; i++)
    {
        temp=a[i];
        a[i]=a[N-i-1];
        a[N-i-1]=temp;
    }
    printf("\n sorted array:\n");
    for(i=0; i<N; i++)
        printf("%4d",a[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值