《经典c程序100例》这个文章是我在百度文库中看到的,看到这个文章心情非常激动,很感激原创者的伟大贡献!太伟大了!!感觉里面的小例子拿来用于练习很能够活跃算法思维。
本文主要是用C++实现《经典c程序100例》
以下程序已经在VC++ 6.0中调试。
【程序1】题目:由1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?
1. 程序主体功能分析:先实现填在百位、十位、个位的数字都是1、2、3、4,组成所有的排列后再排除去掉不满足条件的排列。
程序代码:
#include <iostream>
using namespace std;
int main()
{
/*以下为三重循环*/
for (int i=1;i<5;i++)
{
for(int j=1;j<5;j++)
{
for(int k=1;k<5;k++)
{
if((i!=k)&&(i!=j)&&(j!=k))
/*确保i、j、k三位互不相同
加上括号可以增加程序的可读性 */
cout<<i<<j<<k<<endl;
}
}
}
return 0;
}
2. 添加计算个数的功能:
#include <iostream>
using namespace std;
int main()
{
int n=0;
/*以下为三重循环*/
for (int i=1;i<5;i++)
{
for(int j=1;j<5;j++)
{
for(int k=1;k<5;k++)
{
if((i!=k)&&(i!=j)&&(j!=k))
/*确保i、j、k三位互不相同*/
{
cout<<i<<j<<k<<endl;
n++;
}
}
}
}
cout<<"由1、2、3、4个数字,能组成"<<n<<"个互不相同且无重复数字的三位数!"<<endl;
return 0;
}
运行结果跟数学运算的逻辑推理结果一样,4*3*2=24种(以百位开始推理,百位有4种选择,百位的数字确定后选择后十位有3种可行性选择,而当百位和十位的数字都确定后则个位有2种可行性选择)。
==============================================================
【程序2】
题目:企业发放的奖金根据利润提成。利润(I)低于或等于10万元时,奖金可提10%;利润高于10万元,低于20万元时,低于10万元的部分按10%提成,高于10万元的部分,可可提成7.5%;20万到40万之间时,高于20万元的部分,可提成5%;40万到60万之间时高于40万元的部分,可提成3%;60万到100万之间时,高于60万元的部分,可提成1.5%,高于100万元时,超过100万元的部分按1%提成,从键盘输入当月利润I,求应发放奖金总数?
1.程序分析:请利用划分金额作为分界,分级别计算。程序中,把奖金和利润定义为长整型,如果需要小数点可根据实际需要定义为实型等其他数据类型。
2.程序源代码:
#include <iostream>
using namespace std;
int main()
{
long int i;
int bonus1,bonus2,bonus4,bonus6,bonus10,bonus;
cout<<"请输入利润(I),要求必须是数字:";
//测试的时候如果输入的是小数,编译器会自动隐式转换为整型
cin>>i;
bonus1=100000*0.1;
bonus2=bonus1+100000*0.075;
bonus4=bonus2+200000*0.05;
bonus6=bonus4+200000*0.03;
bonus10=bonus6+400000*0.015;
if(i<=100000)
{
bonus=i*0.1;
}
else if(i<=200000)
{
bonus=bonus1+(i-100000)*0.075;
}
else if(i<=400000)
{
bonus=bonus2+(i-200000)*0.05;
}
else if(i<=600000)
{
bonus=bonus4+(i-400000)*0.03;
}
else if(i<=1000000)
{
bonus=bonus6+(i-600000)*0.015;
}
else
bonus=bonus10+(i-1000000)*0.01;
cout<<bonus<<endl;
if(bonus<=0) cout<<"奖金小于等于0,不用发奖金"<<endl;
/*
如果企业实际执行,利润亏损需要罚钱,可以删除"if(bonus<=0) cout<<"奖金小于等于0,不用发奖金"<<endl;"该句提示语。
*/
return 0;
}
如果输入的是负数,即利润为负数,业绩亏损,系统也是会按照低于或等于10万元时的奖金按照10%算,算出来的结果是负数,即需要对其进行扣钱处罚。如果企业实际执行,只发奖金不扣钱,可以通过"if(bonus<=0) cout<<"奖金小于等于0,不用发奖金"<<endl;"该句给用户提示!
==============================================================
【程序3】
题目:一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?
1. 程序分析:
完全平方即用一个整数乘以自己例如1*1,2*2,3*3等等,依此类推。若一个数能表示成某个自然数的平方的形式,则称这个数为完全平方数。
相邻的两个完全平方数的差=n*n-(n-1)*(n-1)=2n-1。
假设题目中的整数加它加上100后,再加上168的完全平方数开平方后的值为n。
则其相邻的两个完全平方数的差=2n-1<=168;
n<=84.5;
而n必须是整数,则n<=84,n*n<=84*84,则(a+268)小于7056,该是小于1万的。
我们参考《经典c程序100例》该文章,设置程序扩大到在10万以内判断,可以验证我们先前的推论。
将题目中的该整数设为a,该数a加上100后是一个完全平方数(设该完全平方数开方后等于整数x),再加上168又是一个完全平方数(设该完全平方数开方后等于整数y),如果开方后的结果满足该条件,即是结果。
x*x=a+100;
y*y=a+268;
2.程序源代码:
#include <iostream>
#include "math.h"
using namespace std;
int main()
{
long int a,x,y;
for(a=1;a<100000;a++)
{
x=sqrt(a+100); //x为(a+100)后开平方的结果
y=sqrt(a+268);//y为(a+268)后开平方的结果
if((x*x==(a+100))&&(y*y==(a+268)))
{
cout<<a<<endl;
}
//如果一个数的平方根的平方等于该数,这说明此数是完全平方数
}
return 0;
}
运行结果:
21
261
1581
说明:
1、math.h是与数学运算相关的头文件,很常用。
类似的还有stdio.h也是与标准输入输出相关的头文件,也很常用。
如果电脑安装了VC++,可以搜索一下计算机,后缀名为.h的文件就知道有哪些标准头文件了。
常用的头文件非常多,如果平时用的时候不完全知道或者不大了解的时候,当你用到哪个函数,去msdn帮助文件里搜一下,就知道该包含什么头文件了,简单又快速
如果还是不了解,可以百度 谷歌,或者找朋友问问。
2、sqrt函数是用于平方根计算的函数
功 能: 计算一个非负实数的平方根
函数原型: 在VC6.0中的math.h头文件的函数原型为double sqrt(double);
VC 2008后为重载函数,原型为 float sqrt (float),double sqrt (double),double long sqrt(double long)
注意没有int sqrt (int)
3、原文《经典c程序100例》中用printf("%ld\n",i)输出。
%ld 是 printf 函数和其它类似函数中的输出格式控制符, 意思是输出长整型。
C语言中%d和%ld之间的区别:
%d是按整型输出,在C语言中是16位的二进制数范围-32768——32767
%ld是按长整型输出,长度是整型的2倍32位,范围-2147483648---2147483647
==============================================================
【程序4】
题目:输入某年某月某日,判断这一天是这一年的第几天?
1.程序分析:以3月5日为例,应该先把前两个月的加起来,然后再加上5天即本年的第几天,特殊情况,闰年且输入月份大于3时需考虑多加一天。
2.程序源代码:
#include <iostream>
#include "math.h"
using namespace std;
int main()
{
int day,month,year,sum,leap;
cout<<"请输入年份:";
cin>>year;
cout<<"\n请输入月份:";
cin>>month;
cout<<"\n请输入日期:";
cin>>day;
switch(month)
{
case 1:sum=0;
break;
case 2:sum=31;
break;
case 3:sum=59;
break;
case 4:sum=90;
break;
case 5:sum=120;
break;
case 6:sum=151;
break;
case 7:sum=181;
break;
case 8:sum=212;
break;
case 9:sum=243;
break;
case 10:sum=273;
break;
case 11:sum=304;
break;
case 12:sum=334;
break;
default:cout<<"输入的月份错误!";
break;
}
sum=sum+day;//再加上某天的天数
if(year%400==0||(year%4==0&&year%100!=0)) //判断是不是闰年。
//此外,上行也可以写为if((year%400==0)||((year%4==0)&&(year%100!=0)))
leap=1;
else
leap=0;
if(leap==1&&month>2) //如果是闰年并且月份大于2,总天数应该加1天
{
sum++;
}
cout<<"It is the "<<sum<<"th day of "<<year<<"!"<<endl;
return 0;
}
运行结果1:
请输入年份:2001 (假设用户输入2001)
请输入月份:3 (假设用户输入3)
请输入日期:7 (假设用户输入日期7)
It is the 66th day of 2001!
运行结果2:
请输入年份:2000(假设用户输入2000)
请输入月份:4 (假设用户输入4)
请输入日期:5 (假设用户输入日期5)
It is the 96th day of 2000!
运行结果3:
请输入年份:2000(假设用户输入2000)
请输入月份:13 (假设用户输入13,测试输入错误月份提示语)
请输入日期:9 (假设用户输入日期9)
输入的月份错误!It is the -858993450th day of 2000!
从调试结果3来看如果输入的月份错误会有提示,但是如果输入的日期错误,没有提示。该程序有待改进。
因为涉及到每个月份的天数不一样。
其中1-12月分别为31天,28天(闰年为29天),31天,30天,31天,30天,31天,31天,30天,31天,30天,31天。该程序关于日期输入错误的提示功能模块,因为篇幅有限就不再赘述,初步构思可以按照28,29,30,31四类天数用switch语句实现。
以下是摘录自百度百科中关于“闰年”的介绍:
闰年(Leap Year)是为了弥补因人为历法规定造成的年度天数与地球实际公转周期的时间差而设立的。补上时间差的年份为闰年。
精确计算方法
(按一回归年365天5小时48分45.5秒)
①、普通年能被4整除且不能被100整除的为闰年。(如2004年就是闰年,1901年不是闰年)
②、世纪年能被400整除的是闰年。(如2000年是闰年,1900年不是闰年)
③、对于数值很大的年份,这年如果能整除3200,并且能整除172800则是闰年。如172800年是闰年,86400年不是闰年(因为虽然能整除3200,但不能整除172800)(此按一回归年365天5h48'45.5''计算)。
此外,如依照现有太阳年的长度与上述闰年规则,每8000年又约差一日,因此约翰·赫歇尔提议每逢4000的倍数不闰,如西元4000年。但距此一年份来临尚有约二千年之遥,因此还未曾真正纳入规则或实施过。又由于地球公转速率的不稳定与众多影响因素,届时是否需要纳入此规则仍有疑问。
==============================================================
【程序5】
题目:输入三个整数x,y,z,请把这三个数由小到大输出。
1.程序分析:首先,我们将x与y进行比较,如果x>y则将x与y的值进行交换(如果本身x<=y则不交换保持原状),从而实现了x和y的值按照从小到大排序。然后再用x与z进行比较,如果x>z则将x与z的值进行交换,这样能使x最小。
最后再将y和z的值进行比较,如果y>z则将y和z的值进行交换。再将x,y,z输出。
2.程序源代码:
#include <iostream>
using namespace std;
int main(void)
{
int x,y,z,t;
cout<<"请输入3个整数\n";
cout<<"第一个整数:";
cin>>x;
cout<<"第二个整数:";
cin>>y;
cout<<"第三个整数:";
cin>>z;
if (x>y)
{
t=x;
x=y;
y=t;
} /*交换x,y的值*/
if(x>z)
{
t=z;
z=x;
x=t;
}/*交换x,z的值*/
if(y>z)
{
t=y;
y=z;
z=t;
}/*交换z,y的值*/
cout<<"三个数从小到大,分别为:\n"<<x<<endl;
cout<<y<<endl;
cout<<z<<endl;
return 0;
}
==============================================================
【程序6】
题目:用*号输出字母C的图案。
1.程序分析:可先用'*'号在纸上写出字母C,再分行输出。
2.程序源代码:
实现方法一:
#include <iostream>
using namespace std;
int main()
{
cout<<"Hello C-world!\n";
cout<<" ****\n";
cout<<" *\n";
cout<<" * \n";
cout<<" ****\n";
return 0;
}
实现方法二:
#include <cstdio> //定义输入/输出函数
int main()
{
printf("Hello C-world!\n");
printf(" ****\n");
printf(" *\n");
printf(" * \n");
printf(" ****\n");
return 0;
}
==============================================================
【程序7】
题目:输出特殊图案,请在C++环境中运行,看一看,Very Beautiful!
1.程序分析:提示输出的是扩展ASCII码
2.程序源代码:
#include <cstdio> //定义输入/输出函数
int main()
{
char a=176,b=219;
printf("%c%c%c%c%c\n",b,a,a,a,b);//%c是换成ASCII码输出
printf("%c%c%c%c%c\n",a,b,a,b,a);
printf("%c%c%c%c%c\n",a,a,b,a,a);
printf("%c%c%c%c%c\n",a,b,a,b,a);
printf("%c%c%c%c%c\n",b,a,a,a,b);
}
直接复制程序到VC 6.0中看到的结果如下,居然是乱码!!
真心的觉得不漂亮!感觉被题目骗了!
后来转念一想,可能是哪里设置不对。
百度了一下,找到了原因:编号在128~255的是扩展的编码,原本不是作为显示用的,而且我们的控制台默认代码页是“936 (ANSI/OEM -简体中文 GBK)”。如果要显示扩展ASCII码,则将执行这个程序的控制台的的代码页改为 437 (OEM-美国) 即可!
在刚刚乱码的控制台窗口标题栏上 右键--》默认值--》默认代码页 修改为437,再次运行程序就看到了。
==============================================================
【程序8】
题目:输出9*9口诀。
1.程序分析:分行与列考虑,共9行9列,i控制行,j控制列。
2.程序源代码:
#include <cstdio>
int main()
{
int i,j,result;
printf("\n");
for (i=1;i<10;i++)
{
for(j=1;j<10;j++)
{
result=i*j;
printf("%d*%d=%-3d",i,j,result);//%-3d表示输出左对齐,占3位
}
printf("\n");//每一行后换行
}
return 0;
}
运行结果如下图 可以看到等号后面3位是左对齐的,从而形成了整齐的排列:
%3d--可以指定宽度,不足的左边补空格 %-3d--左对齐 表示输出的内容左对齐,输出结果共有3位,不足的话,在结果最后用空格补足占3位 %03d---一种左边补0 的等宽格式,比如数字12,%03d出来就是: 012
==============================================================
【程序9】
题目:要求输出国际象棋棋盘。
1.程序分析:用i控制行,j来控制列,根据i+j的和的变化来控制输出黑方格,还是白方格。
2.程序源代码:
#include <cstdio>
int main()
{
int i,j;
for(i=0;i<8;i++)
{
for(j=0;j<8;j++)
{
if((i+j)%2==0)
{
printf("%c%c",219,219);
}
else
printf(" ");//注意双引号里面是两个空格
}
printf("\n");
}
return 0;
}
%c是换成ASCII码输出,跟上面的【程序7】一样需要设置控制台默认代码页为437 (OEM-美国)后再运行程序。
运行结果:
【程序10】
题目:打印楼梯,同时在楼梯上方打印两个笑脸。
1.程序分析:用i控制行,j来控制列,j根据i的变化来控制输出黑方格的个数。
2.程序源代码:
#include <cstdio>
int main()
{
int i,j;
printf("\1\1\n");//输出两个笑脸
for(i=1;i<11;i++)
{
for(j=1;j<=i;j++)
{
printf("%c%c",219,219);
}
printf("\n");
}
return 0;
}
运行结果可以看到如下:
经典c程序100例==11--20
【程序11】
题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月
后每个月又生一对兔子,假如兔子都不死,问每个月的兔子总数为多少?
1.程序分析: 兔子对数的规律为数列1,1,2,3,5,8,13,21....
2.程序源代码:
#include <iostream>
using namespace std;
int main()
{
long f1,f2;
int i;
f1=f2=1;
cout<<"每个月兔子的总对数,分别为:\n";
for(i=1;i<=20;i++)
{
printf("%12ld %12ld",f1,f2);
if(i%2==0)
{
printf("\n");//控制输出,每行4个
}
f1=f1+f2;/*前两个月加起来赋值给第三个月*/
f2=f1+f2;/*前两个月加起来赋值给第三个月*/
}
return 0;
}
输出结果:
==============================================================
【程序12】
题目:判断101-200之间有多少个素数,并输出所有素数。
1.程序分析:
判断素数的方法:用一个数分别去除2到sqrt(这个数),如果能被整除,则表明此数不是素数,反之是素数。
因为偶数永远不可能为素数,所以从101开始,每次增加2,也就是只考虑奇数。
对于每一个奇数k,从2到k-1,如果在2到k-1之间找到能被k整除的数字,也就是约数,自然不是素数了。
2.程序源代码:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int m,i,k,h=0,leap=1;
cout<<"\n";//C++中尽量不要少用printf函数,printf("\n");
for(m=101;m<=200;m++)
{
k=sqrt(m+1);//sqrt()函数,计算平方根
for(i=2;i<=k;i++)
{
if(m%i==0)
{
leap=0;
break;//这里break;是跳出for循环
}
//其他的情况下,leap值没有被修改依旧为1。
}//如果leap=1的,则为素数,下面实现输出。
if(leap)//if(leap)这里也可以写成 if(leap==1)
{
printf("%-4d",m);//%-4d控制输出左对齐并占4位。
h++;
if(h%10==0)//控制每行输出10个数字
printf("\n");
}
leap=1;
}
printf("\nThe total is %d\n",h);
return 0;
}
程序说明:
1、关于if(leap):
if(leap) 这样判断会被自动转化成一个Boolean量来进行流程的控制,会转化成 true and false 两个量而你说的leap == 1 则只是单纯的恒值的比较。
简单的来说,如果leap = 5,在if(leap){} 这个式子中是成立的,为true而在if( leap == 1){} 则是为假的。
写程序思维要求比较严谨。
2、%-4d的作用:
显示位宽为4的整数(就是数字个数为4,不够4的会空出来凑4个,多了就不管了,照原数据输出)而“-”使得数据从左边被输出(左对齐)。
例如:
int x=12234;
printf("%-4d",x);
输出结果是12234.
3、关于为什么是从2到sqrt:
因为,如果a是合数,则a必有一个因数不大于根号a。
以下是证明:
设a为合数,则a=pq,不妨设 2 <= p <= q。
则 a = pq >= p² 即 p<= 根号a。
证明完毕!
当然如果你一时没有想到是从2算到sqrt,也可以从2算到a(只是电脑多算一些时间)。
4、关于break
break只能用于循环和switch里,它的作用是跳出一层循环或者一个分支switch。是针对最近的那个。
if语句是选择分支语句不是循环。for,while,do while是循环
if语句是顺序执行的,执行完了就结束了。
题外话,continue只是对于循环有效,对于if等其他不是循环的都无效。
==============================================================
【程序13】
题目:打印出所有的“水仙花数”,所谓“水仙花数”是指一个三位数,其各位数字立方和等于该数
本身。例如:153是一个“水仙花数”,因为153=1的三次方+5的三次方+3的三次方。
1.程序分析:利用for循环控制100-999个数,每个数分解出个位,十位,百位。
2.程序源代码:
#include <iostream>
int main()
{
int i,j,k,n;
std::cout<<"'water flower' number is:";
for(n=100;n<1000;n++)
{
i=n/100;//分解出百位
j=n/10%10;//分解出十位
k=n%10;//通过求余取出个位
if(i*100+j*10+k==i*i*i+j*j*j+k*k*k)
{
std::cout<<n<<"\t";
}
}
std::cout<<"\n";
return 0;
}
程序输出结果为:
水仙花数是:153 370 371 407
其中我们可能会对:
i=n/100;//分解出百位
j=n/10%10;//分解出十位
k=n%10;//通过求余取出个位
是否确实正确地取出了有所怀疑。
输入以下,测试验证是否会出现系统自动小数点后逢五进一的问题。
#include <iostream>
int main()
{
int i;
i=679;
std::cout<<i/100<<std::endl;//分解出百位检查
std::cout<<i/10%10<<std::endl;//分解出十位检查
std::cout<<i%10<<std::endl;//个位检查
return 0;
}
测试结果输出了:
6
7
9
ASCII码字符共有256个。不同字符,图形不一样。