根据互联网上流程的经典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 2x3−4x2+3x−6 的根。
牛顿迭代法的公式:
x
i
+
1
=
x
i
−
f
(
x
)
f
′
(
x
)
x_{i+1} = x_i - \frac{f(x)}{f^{\prime}(x)}
xi+1=xi−f′(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=xi−6x2+8x+32x3−4x2+3x−6
/* 牛顿迭代法 */
#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;
}