投影8 省二级C算法考点JJH.docx

上传人:b****7 文档编号:9053095 上传时间:2023-02-03 格式:DOCX 页数:32 大小:55.60KB
下载 相关 举报
投影8 省二级C算法考点JJH.docx_第1页
第1页 / 共32页
投影8 省二级C算法考点JJH.docx_第2页
第2页 / 共32页
投影8 省二级C算法考点JJH.docx_第3页
第3页 / 共32页
投影8 省二级C算法考点JJH.docx_第4页
第4页 / 共32页
投影8 省二级C算法考点JJH.docx_第5页
第5页 / 共32页
点击查看更多>>
下载资源
资源描述

投影8 省二级C算法考点JJH.docx

《投影8 省二级C算法考点JJH.docx》由会员分享,可在线阅读,更多相关《投影8 省二级C算法考点JJH.docx(32页珍藏版)》请在冰豆网上搜索。

投影8 省二级C算法考点JJH.docx

投影8省二级C算法考点JJH

算法考点

非数值计算常用经典算法

基本操作:

交换(*****)

实现变量的值的交换最常用的方法是借助一个临时变量来实现将两个数的值进行交换。

voidswap(intx,inty)

{inttemp;

temp=x;x=y;y=temp;

}

值传递,单向的,如果主函数调用了此函数,尽管形式参数x和y的值交换了,而主函数中的实际参数是不会改变的。

要想实现地址传递,应该用指针实现。

voidswap(int*x,int*y)

{inttemp;

temp=*x;

*x=*y;

*y=temp;

}

函数调用时将实参的地址传递给指针x和y,例如:

swap(&a,&b);实现x和y指向的地址单元的值的交换,即a和b的值的交换。

1.排序(*****)

排序就是将数组中的元素按从大到小的顺序或者从小到大的顺序重新排列。

1)冒泡排序(*****)

下面的函数是按升序从前往后排。

voidBubbleSort(inta[],intn)

{inti,j,tmp;

大数移到了最后

for(i=0;i

{for(j=0;j

if(a[j]>a[j+1])/*从小到大*/

{tmp=a[j];a[j]=a[j+1];a[j+1]=tmp;}

/*交换a[j]与a[j+1],大数后移*/

}

}

2)选择排序(*****)

算法思想:

从待排序的序列中,选择最小的一个记录,与第一个数据交换;然后从不包括第一个记录的序列中选择最小一个与第二个交换;如此重复,直至只剩一个数据为止。

voidSelectSort(inta[],intn)

{inti,j,min_i,tmp;

for(i=0;i

{min=i;/*假设第一个数最小,记录其下标*/

for(j=i+1;j

if(a[j]

/*找最小的,将最小数的下标记录下来*/

if(i!

=min)

{tmp=a[i];a[i]=a[min];a[min]=tmp;}

/*将最小的数与第一个数进行交换*/

}

}

3)插入排序(***)

算法思想:

插入排序的基本操作就是将一个数据插入到已经排好序的有序数组中,从而得到一个新的、个数加1的有序数组。

voidInsertSort(inta[],intn)

{inti,j,tmp;

for(i=1;i

{tmp=a[i];/*空出a[i]单元*/

for(j=i-1;j>=0&&a[j]>tmp;j--)

a[j+1]=tmp?

;

a[j+1]=a[j];/*大于tmp的数向后移位*/

/*tmp归位*/

}

}

2.归并(或合并)(****)

归并就是将两个有序数组A、B合并成另一个有序的数组C(升序或降序)。

算法步骤:

1先在A、B数组中各取第一个元素进行比较,将小的元素放入C中。

2取小的元素所在数组的下一个元素与另一个数组中上次比较后较大的元素比较。

3重复上述比较过程,直到某个数组被先排完。

4将另一个数组剩余元素抄入C中,合并排序完成。

voidmerge(inta[m],intb[n],intc[])

{ia=0;ib=0;ic=0;

while(ia

{if(a[ia]

else{c[ic]=b[ib];ib++;}

ic++;

}

while(ia

/*a中剩余元素抄入c中*/

while(ib

}

3.查找(****)

查找,就是判断一个数是否是数组中的某个元素。

最常见最简单的查找方法为线性法查找,对于已经排过序的数组,可以采用折半法查找。

1)线性法查找

没有排序的数组,只能采用线性法查找

基本思想:

将x与数组中的各个元素从头到尾进行比较,找到返回数组下标,找不到,返回-1。

#defineN10

intfind(inta[N],intkey)

{for(i=0;i

if(a[i]==key){return(i);break;}/*返回数组元素下标*/

if(i==N)return(-1);

}

2)折半法查找

折半查找法也称为二分查找法,只能对有序数组进行查找。

将n个元素分成个数大致相同的两半,取a[n/2]与欲查找的x作比较,如果x=a[n/2]则找到x,算法终止。

如果x

如果x>a[n/2],则我们只要在数组a的右半部分继续搜索x。

#defineN10

intfind(inta[N],intkey)

{intm;

p=0;q=N-1;

/*p为第1个元素的下标,q为最后一个元素的下标*/

while(p<=q)

{m=(p+q)/2;/*m为中间元素的下标*/

if(a[m]==key){return(m);break;}

elseif(key

elsep=m+1;

}

if(p>q)return(-1);

}

4.穷举(***)

穷举法的基本思想是:

一一列举各种可能的情况,并判断哪一种可能是符合要求的解。

这是一种在“没有其它办法的情况的方法”,是一种最“笨”的方法,然而对一些无法用解析法求解的问题往往能奏效,通常采用循环来处理穷举问题。

【例题】有1、2、3、4四个数字,能组成多少个互不相同且无重复数字的三位数?

都是多少?

程序分析:

可填在百位、十位、个位的数字都是1、2、3、4。

组成所有的排列后再去掉不满足条件的排列。

main()

{inti,j,k;

for(i=1;i<5;i++)    /*以下为三重循环*/

 for(j=1;j<5;j++) 

  for(k=1;k<5;k++)

   if(i!

=k&&i!

=j&&j!

=k) /*确保i、j、k三位互不相同*/

    printf("%d,%d,%d\n",i,j,k);

}

数值计算常用经典算法

级数计算(递推法)(*****)

累加(*****)

使用循环时,要注意根据问题确定循环变量的初值、终值或结束条件,更要注意用来表示最后结果的初值。

用c语言实现1+2+3+4+5+……+n的累加。

【方法1】for循环实现

intadd(intn)

{inti,sum=0;

for(i=1;i<=n;i++)sum=sum+i;

returnsum;

}

【方法2】while循环实现

intadd(intn)

{inti,sum;

sum=0;i=1;

while(i<=n)

{sum=sum+i;

i=i+1;

}

returnsum;

}

do-while循环也可以实现累加。

累乘

在累乘之前,一定要将用于存放乘积的变量的值初始化为1。

用c语言求n的阶乘:

n!

=1234…n(n>=0)

intproduct(intn)

{inti,p=1;

for(i=2;i<=n;i++)p=p*i;

returnp;

}

如果n的值比较大,考虑累乘的结果可能会超过32767,函数返回值应定义为长整型,确保程序运行的正确。

longfunc(intn)

{inti;

longp=1;

for(i=2;i<=n;i++)p*=i;

returnp;

}

用递推法求n!

的程序段如下:

for(fac=1,i=2;i<=n;i++)fac=fac*i;

【例题】有一分数序列:

求出这个数列的前20项之和。

本题主要要抓住分子与分母的变化规律。

main()

{intn,t,number=20;

floata=2,b=1,s=0;/*a表示分子,b表示分母*/

for(n=1;n<=number;n++)

 { s=s+a/b;

 t=a;

a=a+b;

b=t;

}

printf("sumis%9.6f\n",s);

}

【例题】求1+2!

+3!

+...+20!

的和

main()

{floatn,s=0,t=1;

for(n=1;n<=20;n++)

 { t*=n;

 s+=t;

 }

printf("1+2!

+3!

...+20!

=%e\n",s);

}

运行结果为:

1+2!

+3!

...+20!

=2.561327e+18

本题将变量定义为float,因为long型数据的范围为-21亿~21亿。

无法容纳求得的结果。

int型的就更不用说了,表示范围只有-32768~32767。

【例题】以下程序的功能是:

根据公式和精度计算π的近似值。

#include

#include

doublePI(doubleeps)

{doubles=0,t=1.0;intn;

for(n=1;___________;n++)

{s+=t;t=t*(n-1)/(2*n-1)?

?

__________;}

return2.0*s;

}

voidmain()

{doublee=1e-6;

/*e是计算精度要求,这里表示允许运算结果值在小数点后第6位有误差*/

printf("%f",_________________);

}

【例题】以下程序通过给出的公式计算π的近似值,计算过程在所加项的值小于10-6时终止。

#include

main()

{doublesum=0.5,t,t1,t2,t3;

intodd=1,even=2;

t=t1=t2=1.0;t3=0.5;

while(t>1e-10)

{t1=____t1*odd/even?

?

_____;

odd+=2;even+=2;

t2=1.0/odd;

t3=___t3*0.5*0.5?

?

________;

t=t1*t2*t3;

sum+=t;

}

printf("\nPI=%.8lf",________sum_____;

}

解决各类问题的一般算法

数组问题

1.求最大、最小值(*****)

1)查找一维数组a[]中的最大值,n为数组的大小

intfunmax(inta[],intn)

{inti,max=a[0];

for(i=1;i

if(max>a[i])max=a[i];

returnmax;

}

2)查找二维数组a中的最小值

有一个3×4的矩阵,求所有元素的最小值。

二维数组作函数的参数,第一维的长度可以缺省,第二维的长度不能缺省。

intfunmin(inta[][4])

{inti,j,min;

min=a[0][0];

for(i=0;i<3;i++)

for(j=0;j<4;j++)

if(a[i][j]

returnmin;

}

2.求和及平均值(*****)

求数组的平均值,先用循环将数组的所有元素相加,最后返回所得的和除以数组元素的个数。

intaverage(inta[],intn)

{inti,avg=0;

for(i=0;i

/*若avg的初值为a[0],则i从1开始*/

returnavg/n;

}

若求数组的和,则return语句改为returnavg。

若所求的数组的平均值不是从第一个元素开始的,不管从那个元素开始,只要将开始元素的地址作为实际参数即可。

例如,数组a共有20个元素,求最后5个元素的平均值的调用方式为:

average(&a[15],5);

3.计数(*****)

求满足要求的数的个数。

一般在循环中对每一个元素都用if语句进行判断,满足条件的话,计数的变量增1。

例如:

对数组中的n个学生成绩,求不及格人数的个数。

intcount(inta[],intn)

{intc=0;

for(i=0;i

if(a[i]<60)c++;

returnc;

}

4.数组元素逆置(*****)

算法思想:

将数组元素的第一个与最后一个元素交换位置,第二个元素与倒数第二个元素交换位置……。

需要注意的是,只能遍历数组的一半元素,如果遍历整个数组,每个元素都做了两次交换,最终又回到原来的位置上。

exchange(inta[],intn)

{inti,t;

for(i=0;i

{t=a[i];a[i]=a[n-i-1];a[n-i-1]=t;}

}

5.在数组中插入一个数

1)在数组的指定位置插入一个数

如果在a[i]后插入一个x,从最后一个元素开始,将a[i+1]以后的元素往后移,空出位置后将x放在a[i+1]位置处。

for(j=N-1;j>i;j--)a[j+1]=a[j];/*移位*/

a[i+1]=x;/*插入x*/

2)在已排序的数组中插入一个数

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

首先判断此数是否大于最后一个数,然后再考虑插入中间的情况,找插入点,先将插入点之后的数,依次后移一个位置。

#defineN6

voidinsert(inta[N],intnum)

{inti,j;

if(num>a[N-2])a[N-1]=num;/*插在最后*/

else

for(i=0;i

if(a[i]>num)/*找插入点,插在a[i]位置*/

{for(j=N-2;j>=i;j--)a[j+1]=a[j];

/*将a[i]以后的元素从最后一个元素开始后移*/

a[i]=num;/*将num放在a[i]处*/

break;

}

}

6.删除数组中的一个元素a[i]

删除数组中的元素a[i],就是将a[i]以后的元素往前移一个位置。

voiddel(inta[],intn,inti)

{intj;

for(j=i;j

}

 

整数问题

1.素数问题

素数是指除1和本身外不能被其他任何整数整除的正整数。

1)判断m是否是素数的函数

#include

intprime(intm)

{inti,k;

k=sqrt(m);/*k是不大于m的平方根的最大整数*/

for(i=2;i<=k;i++)

if(m%i==0)return0;/*不是素数,返回0*/

return1;

}

2)把m~n范围内的素数依次放入数组a中,返回素数个数。

#include

intprime(inta[N],intm,intn)

{inti,k,j;

j=0;/*j为素数的个数*/

for(i=m;i<=n;i++)

{for(k=2;k<=sqrt(i);k++)

if(i%k==0)break;/*i不是素数,内循环结束*/

if(k>sqrt(i))a[j++]=i;/*i为素数,存入数组*/

}

returnj;

}

2.求最大公约数和最小公倍数

1)求最大公约数(欧几里得算法)

最大公约数的算法也叫欧几里得算法,采用的是辗转相除法求两数m、n最大公约数,其算法步骤如下:

1对于已知两数m和n,;

2将m除以n得余数r;

3若r为0,则n为求得的最大公约数,算法结束,否则执行下一步;

4n赋给m,r赋给n,再重复执行上面的两步。

算法结束时,m中所存放的值即为最大公约数。

gcd(intm,intn)

{intt,r;

if(m

while(n)

{r=m%n;/*求余*/

m=n;n=r;/*窜位,准备下次求余*/

}

returnm;

}

2)求最小公倍数

算法:

两数之积除以最大公约数所得的值即为最小公倍数

gcd(intm,intn)

{intt,r,p;

p=m*n;

while(n)

{r=m%n;m=n;n=r;}

returnp/m;

}

如果在同一个程序中,可以直接调用最大公约数的函数。

gcd(intm,intn)

{intt,r;

p=m*n;

returnp/gcd(m,n);

}

3.整数拆分与拼接

1)拆整数

求一个整数的位数及将各位数字放在数组中,返回整数的位数。

intpdigit(longn,inta[])

{inti=0,k;

while(n)

{a[i++]=n%10;/*取余数*/

n=n/10;/*求整数,去掉余数后的数*/

}

return(i);

}

下面的函数是求整数n的各位数字之和。

intsum(intn)

{ints=0;

while(n)

{s=s+n%10;n=n/10;}

return(s);

}

若求各位数字之积,只要将s的初值“0”改为“1”,“加”改成“乘”即可。

2)拼整数

在键盘输入若干个数字,直到输入负数为止,输出这些数字组成的数,先输入的数字作为最高位。

main()

{longnum=0;

intn;

scanf("%d",&n);

while(n>=0)

{num=num*10+n;

scanf("%d",&n);

}

printf("%ld",num);

}

4.求反序数和回文数

1)求反序数

将一个数的数字排列顺序完全颠倒过来,就变成另一个数,这个数就是该数的反序数,如123的反序数为321。

intinte(intn)

{intnum=0;

while(n)

num=num*10+n%10;

n=n/10;

{

 

}

return(num);

}

2)求回文数

一个数与它的反序数相等,这样的数称为回文数。

例如12321,6336等就是回文数。

判断一个数是否是回文数,先求出它的反序数,再判断两者是否相等。

①判断n是否是回文数的函数

intpalin(intn)

{ints=0;

m=n;

反序数

while(m)

{s=s*10+m%10;

m=m/10;

}

if(s==n)return

(1);

elsereturn(0);

}

②求指定范围内的回文数

写一个函数,求指定范围内(m1~m2之间)的回文数,保存到指定的数组中,并返回回文数的个数。

intpalin(longm1,longm2,longx[])

{longi,n,s;/*s是i的回文数*/

intk=0;/*k回文数个数,数组下标*/

for(i=m1;i<=m2;i++)

{n=i;s=0;

while(n)/*求反序数*/

{s=s*10+n%10;

n=n/10;

}

if(i==s){x[k]=i;k++;}/*若是回文数,放入数组a中*/

}

returnk;/*返回回文数的个数*/

}

5.因子、完全数、互满数对

1)求a的因子并存放在数组中

因子是指能被a整除的数,包含1和该数本身,真因子包含1不包含本身。

intfun(inta,intx[N])

{inti,j=0;

for(i=1;i<=a;i++)

if(a%i==0)x[j++]=i;

returnj;/*返回因子的个数*/

}

2)找指定范围内的完全数

完全数是指一个正整数的所有真因子之和等于本身的数,因子包含1但不包含本身,例如:

:

6=1+2+3,28=1+2+4+7+14,所以6和28是完全数。

intfun(inta[N],intm,intn)

{inti,j,s;

intk=0;

for(i=m;i<=n;i++)

{s=0;for(j=1;j

if(i%j==0)s=s+j;

if(i==s)a[k++]=i;

}

returnk;

}

3)互满数对(亲密数对)

互满数对是指两个数中,其中的一个数的真因子之和都等于另一个数。

即a的真因子之和为b,b的真因子之和为a。

如:

220与184,1184与1210就是互满数对。

intfun(ints[][2],intm1,intm2)

{ints1,s2,count,a,i,j;

count=0;

for(a=m1;a<=m2;a++)

{s1=1;s2=1;

for(i=2;i

for(j=2;j

if((s2==a)&&(a

{s[count][0]=a;

s[count][1]=s1;

count++;

}

}

returncount;

}

6.求满足条件的数或数对

本类型的题目是近年考得比较多的类型,其变化也比较多,需要分析,灵活运用。

比较简单的如同构数,还有典型的Armstrong数。

实际上,素数、回文数、完全数等都是属于满足要求的数。

很多问题都是由基本的算法变化来的。

1)同构数

同构数是其值等于其右边数字平方数的整数。

如25,36都是同构数(25=52,36=62)。

下面的程序是求1~99之间的所有同构数。

main()

{inti,k;

for(i=1;i<100;i++)

{k=i%10;/*求未位数*/

if(k*k==i)printf(“%d,“,i);/*输出满足要求的数*/

}

2)Armstrong数

一个n位的正整数,其各位数的n次方之和等于这个数,称这个数为Armstrong数。

例如,153=13+53+33。

1634=14+64+34+44。

下面的程序求所有三位和四位数的Armstrong

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 总结汇报 > 实习总结

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1