程序设计中的技巧Word文件下载.docx
《程序设计中的技巧Word文件下载.docx》由会员分享,可在线阅读,更多相关《程序设计中的技巧Word文件下载.docx(24页珍藏版)》请在冰点文库上搜索。
![程序设计中的技巧Word文件下载.docx](https://file1.bingdoc.com/fileroot1/2023-5/4/9199b04c-1950-42a2-9c48-5f625f667c28/9199b04c-1950-42a2-9c48-5f625f667c281.gif)
for(i=2;
{k=1
while(i*k<
=n)
{a[i*k]=1-a[i*k];
k=k+1;
}
printf(“%d”,a[i]);
注:
程序中第二个for循环i枚举的不是灯的编号,而是编号为i的同学,其内层循环中,就将包含i因素的灯的编号为“i*k”的灯,改变其状态。
程序中还用计算省去了用if语句判断编号能被哪些数整除的过程。
【例3】右图中所示的圆圈中,我们把相隔一个数据的两个数(如1和10,3和5,3和6)称作是“一对数”,试编写程序求出乘积最大的一对数和乘积最小的一对数。
输出格式如下:
max:
?
*?
=?
min:
其中?
表示:
找到的满足条件的数和乘积。
1
1716
810
1216
51
99
315
812
6
实现要点
1)数据有前后“位置”关系,必须用数组来存储。
数组定义为a[num],则有a[0]——a[num-1]共num个元素。
2)用i代表下标,题目就是顺序将a[i-1]与a[i+1]相乘,求出乘积的最大值和最小值即可。
3)关键是i=num-1时,保证i+1的“值”是0;
当i=0时,保证i-1的“值”是num-1,把数组当成圆圈操作通过求余运算很容易实现:
当i=num-1时,(i+1)%num等于0;
当i=0时(num+i1)%num等于num-1。
4)用变量Max记录当前最大的乘积,m、n为对应的两个乘数;
变量min记录当前最小的乘积,s、t为对应的两个乘数。
{intmax=1,min=32767,a[100],num,i,k,m,n,s,t;
num);
for(i=0;
num;
i++)scanf(“%d”,&
a[i]);
{p=(num+i-1)%num;
q=(i+1)%num;
k=a[p]*a[q];
if(k>
max){max=k;
m=a[p];
n=a[q];
if(k<
min){min=k;
s=a[p];
t=a[q];
printf(”max=%d*%d=%d”,m,n,max);
printf(”min=%d*%d=%d”,s,t,min);
2、构造下标
【例】请编写程序统计100人的身高分布,分布等级:
180以上、175—180、170—175、165—170、160—165、155-160、155以下。
此类问题表面看不太适合用switch语句来完成。
因为即使身高是整数若不借助数学运算至少也有20多种情况,需要20多个case子句。
但若注意到每个等级基本是5分一段,通过除法运算将成绩(变量sg)除以5后,分支最多也就只有6个了。
{intsg,k,s[7],t;
printf(“Input%dheight:
”,100);
for(k=1;
k<
=100;
k++)
sg);
if(sg<
0||sg>
300)
//通过计算t=sg/5-30使七类统计区间与数组下标对应,提高了程序效率。
{printf(“Inputerror!
,Inputagain”);
k--;
continue;
}
t=sg/5-30;
if(t<
0){s[0]=s[0]+1;
t=0;
elseif(t>
=6){s[6]=s[6]+1;
t=6;
elses[t]=s[t]+1;
for(t=0;
=6;
t++)
switch(t)
{case0:
printf(“<
155:
%d”,s[0]);
break;
case1:
printf(“155——160:
%d”,s[1]”);
break;
case2:
printf(“160——165:
%d”,s[2]”);
case3:
printf(“165——170:
%d”,s[3]”);
case4:
printf(“170——175:
%d”,s[4]”);
case5:
printf(“175——180:
%d”,s[5]”);
case6:
printf(“>
180:
%d”,s[6]”);
二、标志量的妙用
【例】冒泡排序算法的改
冒泡排序算法的基本思想就是:
相邻数据比较若逆序则交换,逐渐将小数据冒到数组的前面,大的数据则沉到数组的后面,从而完成排序工作。
☆假设原有的数据本来就是从小到大有序的,则原有算法仍要做n-1趟比较操作,事实上一趟比较下来,若发现没有进行过交换,就已经说明数据已全部有序,无需进行其后的比较操作了。
☆数据原本有序的概率并不高,但经过少于n-1趟操作后,数据已经有序的概率却非常高。
为提高效率,可以对冒泡排序算法进行改进,当发现某趟没有交换后就停止下一趟的比较操作。
☆用标志量来记录每趟交换数据的情况,如flag=0表示没有进行过交换,一但有数据进行交换则置flag为1,表示已进行过交换。
当一趟比较交换完成后,若flag仍为0时,则无需进行下一趟操作,否则若flag为1时,只能继续进行下一趟操作。
改进后的程序如下:
main()
{inti,j,t,n,a[100],flag;
printf(“inputdatanumber(<
100):
”);
scanf(“%d”,&
printf(“input%ddata:
”,n);
for(i=0;
n;
flag=1;
for(i=1;
=n-1&
&
flag==1;
{flag=0;
for(j=n-1;
j>
=i;
j--)
if(a[j]<
a[j-1]){t=a[j];
a[j]=a[j-1];
a[j-1]=t;
i++)printf("
%d"
a[i]);
程序说明:
1)排序前“for(i=1;
i++)之前”的flag=1;
是为了保证循环的开始。
2)内层循环外的flag=0;
是假设这趟比较中没有交换,一但发生交换操作在内层循环中就置flag=1;
,以保证继续下一趟操作。
2、表示复杂情况
【例1】编写程序判定从键盘输入n个数据互不相等。
{inta[100],i,j,t,n;
for(i=1;
t=1;
=n-1;
for(j=i+1;
if(a[i]==a[j]){t=0;
if(t==1)printf(“Norepeat”);
elseprintf(“repeat”);
【例2】输入三个数值,判断以它们为边长是否能构成三角形,是否属于特殊三角形:
等边、等腰、直角。
可能的输出情况:
1)不构成三角形
2)构成等边三角形
3)构成等腰三角形
4)构成直角三角形
5)构成一般三角形
其中情况3)、4)可能同时输出,而其它几种若同时输出就不合理了。
情况1)与其它情况互斥,容易分支。
情况5)应该在三角形不属于2)3)4)三种情况时的输出。
关键是情况4)与情况2)、3)不是简单的互斥关系,需要通过标志量来得到合理的输出。
{inta,b,c,flag;
printf(“Input3number:
scanf(“%d%d%d”,&
a,&
b,&
c);
if(a>
=b+c||b>
=a+c||c>
=a+b)
printf(“don’tformatriangle”);
else
if(a*a==b*b+c*c||b*b==a*a+c*c||c*c==a*a+b*b){printf(“formaright-angletriangle”);
if(a==b&
b==c)
{printf(“formaequilateraltriangle”);
elseif(a==b||b==c||c==a)
{printf(“formaequalhaunchtriangle”);
if(flag==0)printf(“formatriangle”);
【例3】编写程序,求任意三个数的最小公倍数。
#include<
stdio.h>
max(intx,inty,intz)
{if(x>
y&
x>
z)return(x);
elseif(y>
x&
y>
z)return(y);
elsereturn(z);
main()
{intx1,x2,x3,t=1,i,flag,x0;
scanf(“%d%d%d”,&
x1,&
x2,&
x3);
for(i=2;
=x0;
{flag=1;
while(flag)
{flag=0;
if(x1%i==0){x1=x1/i;
if(x2%i==0){x2=x2/i;
if(x3%i==0){x3=x3/i;
if(flag==1){t=t*i;
x0=max(x1,x2,x3);
}
printf(“Theresultis%d\n”,t);
三信息数字化
1逻辑类问题
【例1】警察局抓了a,b,c,d四名偷窃嫌疑犯,其中只有一人是小偷。
审问中
a说:
“我不是小偷。
”
b说:
“c是小偷。
c说:
“小偷肯定是d。
d说:
“c在冤枉人。
现在已经知道四个人中三人说的是真话,一人说的是假话,问到底谁是小偷?
将a,b,c,d将四个人进行编号,号码分别为1,2,3,4。
则问题可用枚举尝试法来解决。
实例要点:
用变量x存放小偷的编号,则x的取值范围从1取到4,就尝试了他们中的某人是小偷的所有情况。
四个人所说的话就可以分别写成:
a说的话:
x!
=1b说的话:
x=3
c说的话:
x=4d说的话:
=4或not(x=4)
注意利用前面学习到的技巧,在x的枚举过程中,当这四个逻辑式的值相加等于3时,即表示“四个人中三人说的是真话,一人说的是假话”,所以以此为定解条件。
{intx;
for(x=1;
x<
x++)
if((x!
=1)+(x==3)+(x==4)+(x!
=4)==3)
printf(“%cisathief.”,chr(64+x));
运行结果:
cisathief.
程序说明;
为了程序的方便运行我们对人名进行了数字化,但结果的形式还要符合题目的描述,所以输出时,将数字转化为对应的字母。
这个程序可以方便的改写成PASCAL或BASIC程序,就C语言而言程序还可直接写成如下形式:
for(x=’a’;
=’d’;
if(((x!
=’a’)+(x==’c’)+(x==’d’)+(x!
=’d’))==3)
printf(“%cisathief.”,x);
【例2】三位老师对某次数学竞赛进行了预测。
他们的预测如下:
甲说:
学生A得第一名,学生B得第三名。
乙说:
学生C得第一名,学生D得第四名。
丙说:
学生D得第二名,学生A得第三名。
竞赛结果表明,他们都说对了一半,说错了一半,并且无并列名次,试编写程序输出A、B、C、D各自的名次。
用数1,2,3,4分别代表学生a,b,c,d获得的名次。
问题就可以利用三重循环把所有的情况枚举出来。
{inta,b,c,d;
for(a=1;
a<
a++)
for(b=1;
b<
b++)
if(a!
=b)
for(c=1;
c<
c++)
if(c!
=a&
c!
{d=10-a-b-c;
if(d!
d!
=b&
=c)
if(((a==1)+(b==3))==1&
((c==1)+(d==4))==1
&
((d==2)+(a==3))==1)
printf(“a=%d,b=%d,c=%d,d=%d”,a,b,c,d);
a=4,b=3,c=1,d=2
2智巧类问题
【例1】填写运算符
输入任意5个数x1,x2,x3,x4,x5每相邻两个数之间填上一个运算符+、-、*或/。
在填入四个运算符后,使得表达式值为一个指定值y(y由键盘输入)。
求出所有满足条件的表达式。
实现要点:
?
模仿人去试填所有的运算符,结果是什么
1)枚举法解题
2)若当前运算符轮到‘/’则运算符右端的数必须非零,因为零不能当除数。
3)现在接着考虑‘+、-、*、/’应如何表示,才能方便程序对表达式的求值?
4)如何处理“先乘除/后加减”的优先顺序?
模拟计算:
为了解决运算的优先级问题,我们设置如下变量:
f----减去标志。
减法运算时,置f=-1,否则f=1;
q----若当前运算符为+(-)时,q存贮运算符的左项值;
若当前运算符为*(/)时,q存贮两数乘(除)后结果;
p----累加器。
每填一个算符p=p+f*q。
{intj,k,f,i[5],total;
floatn[6],p,q;
charc[5]={‘‘,’+’,’-’,’*’,’/’};
printf(“\ninputfivenumber”);
for(j=1;
=5;
j++)
scanf(“%f”,&
n[j]);
total=0;
for(i[1]=1;
i[1]<
=4;
i[1]++)
if((i[1]<
4)||(n[2]!
=0))
for(i[2]=1;
i[2]<
i[2]++)
if((i[2]<
4)||(n[3]!
for(i[3]=1;
i[3]<
i[3]++)
if((i[3]<
4)||(n[4]!
for(i[4]=1;
i[4]<
i[4]++)
if((i[4]<
4)||(n[5]!
=0))
{p=0;
q=n[1];
f=1;
for(k=1;
k++)
switch(i[k])
{case1:
p=p+f*q;
q=n[k+1];
f=-1;
q=q*n[k+1];
q=q/n[k+1];
if(p+f*q==n[0])
{total++;
printf(“\ntotal:
%5d:
”,total);
for(k=1;
printf(“%f%c”,n[k],c[i[k]]);
printf(“%f=%f”,n[5],n[0]);
if(total%20==0){每20个方案为一屏,逐屏显示}
{printf(“pressentertocontinue”);
getchar();
思考:
1.四个for循环后的四个if语句的作用是什么?
2.四个数组元素i[1]、i[2]、i[3]、i[4]代表四个运算符,定义的作用是什么?
【例2】有10箱产品每箱有1000件,正品每件100克。
其中的几箱是次品,次品每件比正品轻10克,问能否用秤只称一次,就找出哪几箱是次品。
分析;
若知道次品箱子的个数为1,则将箱子从1-10编号后分别取1——10个产品称重就可以了。
但不知道有几箱是次品,还按以上方法,则无法确定那几箱是次品,如当差30克时,有可能是第三箱,也有可能是1,2两箱。
而分别取20,21,22……29就解决了这个问题。
{inti,k,n,w1=0,w2=0,t=1;
printf(“\nInputthenumberofboxes:
”);
scanf(“%ld”,&
printf(“\n”);
for(i=1;
{printf(“%dboxtake%dletter.”,i,t);
w1=w1+t;
t=t*2;
w1=w1*100;
printf(“\nnormalweight%d”,w1);
printf(“\nInputrealityweight”);
w2);
w1=(w1-w2)/10;
{k=0;
while(w1-t>
=0){t=t*2;
printf(“\n%disbad”,k);
w1=w1-t/2;
【例3】编写程序对输入的一个整数,判断它能否被3,5,7整除,并输出以下信息之一:
1)能同时被3,5,7整除;
2)能被其中两数(要指出哪两个)整除;
3)能被其中一个数(要指出哪一个)整除;
4)不能被3,5,7任一个整除。
{longn;
intk;
printf(“\nPleaseenteranumber:
scanf(“%1d”,&
k=(n%3==0)+(n%5==0)+(n%7==0)
switch(k)
{case3:
printf(“\nAll”);
printf(“\ntwo”);
printf(“\none”);
case0:
printf(“\nnone“);
程序2:
printf(“\nPleaseenteranumber:
k=(n%3==0)+(n%5==0)*2+(n%7==0)*4
{case7:
bresk;
printf(“\n5and7is”);
printf(“\n3and7is”);
printf(“\n7is”);
printf(“\n3and5is”);
printf(“\n5is”);
printf(“\n3is”);
◇程序中k表示整除的情况值。
程序1中,k的范围是0——3可以表示四种情况,而程序2中,为k赋值的表达式是:
(n%3==0)+(n%5==0)*2+(n%7==0)*4,k的范围是0——7可以表示八种情况。
四高精度数据计算——加法运算(十位以上的整数运算)
需要思考的问题:
1、数据的存储
运算:
整型数组,一个元素存储一位
输入:
位数不固定,用整型数组不方便字符串数组
2、字符——数据的转换
‘i’–’0’ii=0,1,2,3,……9
3、数据的运算
由低位到高位逐步运算,考虑进位问题。
主要变量定义:
s1,s2---字符数组(用于存储键盘输入的两个加数);
n1,n2---两个加数的位数;
n0---两个加数较小的位数
n-开始代表两个加数中较大的高精度数据的位数,最后代表结果位数;
a---一个整型数组用于存储计算结果;
b---整型记录运算的中间过程;
d---记录每次的进位。
#include“string.h”#include“stdio.h”
{inta[256],i,j,k,b,d,n,n0,n1,n2;
chars1[256],s2[256],t[256];
printf(“inputtwoaddends:
gets(s1);
gets(s2);
n1=strlen(s1);
n2=strlen(s2);