elsep=m+1;
}
if(p>q)return(-1);
}
7.级数计算(递推法)
递推法是利用问题本身所具有的一种递推关系求问题解的一种方法。
简单地说,就是后一项的值利用前面已求得的项的值得到,典型的递推算法如Fibonacci数列(斐波那契数列),后一项为前两项的和。
基本操作中的累加与累乘都可以看作递推法。
递推公式包括两部分:
开始项的值,以及从前面一、两项得到下一项的计算方法。
用递推式比通项公式算得要快,因为计算每一项都充分利用了前一项的计算结果。
例如,有一分数序列:
…求出这个数列的前20项之和。
(见教材)
8.求最大、最小值
(1)查找一维数组a[]中的最大值,n为数组的大小
intfunmax(inta[],intn)
{inti,max=a[0];
for(i=1;iif(max>a[i])max=a[i];
returnmax;
}
(2)查找二维数组a中的最小值
有一个3×4的矩阵,求所有元素的最小值及该元素的行号列号。
因为函数只能返回一个值,要想得到最小元素的行号和列号,需要用指针作函数的参数。
intfunmin(inta[][4],int*min_i,int*min_j)
{inti,j,min;
min=a[0][0];
for(i=0;i<3;i++)
for(j=0;j<4;j++)
if(a[i][j]{min=a[i][j];*min_i=i;*min_j=j;}
returnmin;
}
main()
{inti,j,min,min_i,min_j,a[3][4]={{3,6,9,12},{2,8,4,6},{5,7,9,10}};
min=funmin(a,&min_i,&min_j);
printf("\nmin=%d,min_i=%d,mim_j=%d\n",min,min_i,min_j);
}
运行结果为:
min=2,min_i=1,mim_j=0
二维数组作函数的参数,第一维的长度可以缺省,第二维的长度不能缺省。
9.求和及平均值
求数组的平均值,先用循环将数组的所有元素相加,最后返回所得的和除以数组元素的个数。
floataverage(inta[],intn)
{inti;floatavg;
avg=0;
for(i=0;ireturnavg/n;/*若求数组的和,则返回avg,最好将avg变量用sum表示*/
}
若所求的数组的平均值不是从第一个元素开始的,不管从哪个元素开始,只要将开始元素的地址作为实际参数即可。
例如,数组a共有20个元素,求最后5个元素的平均值的调用方式为:
average(&a[15],5);
最后5个元素的第一个元素为a[15]。
10.计数
求满足要求的数的个数。
一般在循环中对每一个元素都用if语句进行判断,满足条件时,计数的变量增1。
例如,对数组中的n个学生成绩,求不及格人数的个数。
intcount(inta[],intn)
{intc=0,i;
for(i=0;iif(a[i]<60)c++;
returnc;
}
11.数组元素逆序
voidinv(inta[],intn)
{inti,j,t;
for(i=0,j=n-1;i{t=a[i];a[i]=a[j];a[j]=t;}
}
教材237页也可,或者238页用指针。
12.在数组中插入一个数、删除一个元素、数组元素移位
(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,要求按原来的规律将它插入数组中。
首先判断此数是否大于最后一个数,然后再考虑插入中间的情况,找插入点,先将插入点之后的数依次后移一个位置。
#defineN10
voidinsert(inta[N],intnum)
{inti,j;
if(num>a[N-2])a[N-1]=num;/*插在最后*/
else
for(i=0;iif(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;
}
}
(3)删除数组中的一个元素a[i]
删除数组中的元素a[i],就是将a[i]以后的元素往前移一个位置。
voiddel(inta[],intn,inti)
{intj;
for(j=i;j}
(4)数组元素移位
将数组中的一个元素a[i]移动到指定的位置上。
例如,将一维数组下标为i的元素移到第j的位置。
实际上先将该元素删除,然后再将其插到指定位置,元素在删除前先存放在临时变量中。
voidmove(inta[],intn,inti,intj)
{intk,t;
t=a[i];
for(k=i;kfor(k=n-1;k>=j;k--)a[k+1]=a[k];/*a[j]后的元素都要往后移位*/
a[j]=t;/*插入*/
}
上面函数中的两个for可以合并为一个for,就是将a[i]与a[j]之间的元素往前移一位:
for(k=i;k若需要移动多个元素,则定义一个数组,用来临时存放需移动的元素,移动时在前面加上循环。
例如,移动字符串中的内容。
移动的规则如下:
把第1到第m个字符平移到字符串的最后,把第m+1到最后的字符串移到字符串的前部。
若字符串中原有的内容为:
ABCDEFGHIJK,m的值为3,则移动后,字符串中的内容应该是DEFGHIJKABC。
voidfun(chara[],intm)
{chart[80];inti,j,n;
n=strlen(a);
for(i=0;ifor(i=m,j=0;ifor(i=0;i}
main()
{chara[80]="ABCDEFGHIJK";intm=3;
fun(a,m);
printf("%s",a);
}
13.素数问题
(1)判断m是否是素数的函数
#include/*用sqrt函数必须包含数学库函数math.h*/
intprime(intm)
{inti,k;
k=sqrt(m);/*k是不大于m平方根的最大整数*/
for(i=2;i<=k;i++)
if(m%i==0)return0;/*不是素数,返回0*/
return1;/*素数返回1*/
}
(2)把m~n范围内的素数依次存入数组a中,返回素数个数
#include
intprime(inta[N],intm,intn)
{inti,k,j;
j=0;/*j为数组a的下标,最终结果为素数的个数*/
for(i=m;i<=n;i++)
{for(k=2;k<=sqrt(i);k++)/*判断i是否是素数*/
if(i%k==0)break;/*i不是素数,内循环结束*/
if(k>sqrt(i))a[j++]=i;/*i是素数,存入数组a,下标增1*/
}
returnj;/*返回素数个数*/
}
14.求最大公约数和最小公倍数
(1)求最大公约数(欧几里得算法)
intgcd(intm,intn)
{intt,r;
if(m可以缺省*/
while(n)
{r=m%n;/*求余*/
m=n;n=r;/*窜位,准备下次求余*/
}
returnm;/*返回最大公约数*/
}
(2)求最小公倍数(两数之积除以最大公约数所得的值即为最小公倍数)
intlcd(intm,intn)
{intt,r,p;
p=m*n;/*保留两数乘积*/
while(n)/*求最大公约数*/
{r=m%n;m=n;n=r;}
returnp/m;/*返回最小公倍数*/
}
如果在同一个程序中,可以直接调用最大公约数的函数:
returnm*n/gcd(m,n);
15.整数拆分与拼接
(1)拆整数
求一个整数的位数及将各位数字存放在数组中,返回整数的位数。
intcdigit(longn,inta[])
{inti=0,k;
while(n)
{a[i++]=n%10;/*将余数放入数组a中,数组下标增1*/
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);
}
②将数组a中的数拼成整数。
longpdigit(inta[],intn)
{longnum=0;inti;
for(i=0;ireturn(num);
}
main()
{inta[5]={3,2,7,6,7};
printf("\nnum=%ld\n",pdigit(a,5));
}
16.求反序数和回文数
(1)求反序数
将一个数的数字排列顺序完全颠倒过来,就变成另一个数,这个数就是该数的反序数,如123的反序数为321。
求反序数的方法是先将一个数从个位开始用取余数拆分开来,再将拆开的数字拼成整数。
即将拆整数和拼整数两个函数结合起来即可,边拆边拼。
longinte(longn)
{longnum=0;
while(n)
{num=num*10+n%10;
n=n/10;
}
return(num);
}
(2)求回文数
一个数与它的反序数相等,这样的数称为回文数。
如12321,6336等就是回文数。
①判断m是否是回文数
判断一个数是否是回文数,先求出它的反序数,再判断两者是否相等。
longpalin(longm)
{longs=0,n;
n=m;/*将m存入n中*/
while(n){s=s*10+n%10;n=n/10;}/*求反序数*/
if(s==m)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;/*返回回文数的个数*/
}
函数调用时,数组a定义为长整型,输入输出格式为“%ld”,常量后面要加字母“l”,例如,求1000000~200000之间的回文数的调用形式为:
n=palin(100000l,120000l,a);
其中,n为函数返回的回文数的个数。
17.因子、完全数、互满数对
(1)求a的因子并存放在数组中
因子是指能被a整除的数,包含1和该数本身,真因子包含1不包含本身。
例如,6的因子为1,2,3,6,真因子为1,2,3。
intfun(inta,intx[])
{inti,j=0;
for(i=1;i<=a;i++)/*求a的因子,若求真因子将i<=a改为iif(a%i==0)x[j++]=i;/*i是a的因子,存入数组x中,下标增1*/
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;/*对指定范围内的每个数i都要求其因子之和s*/
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)/*求m1~m2的互满数对*/
{ints1,s2,count,a,i,j;
count=0;
for(a=m1;a<=m2;a++)
{s1=1;s2=1;/*1也是真因子*/
for(i=2;iif(a%i==0)s1=s1+i;/*a的真因子之和为s1*/
for(j=2;jif(s1%j==0)s2=s2+j;/*s1的真因子之和为s2*/
if((s2==a)&&(a{s[count][0]=a;
s[count][1]=s1;
count++;
}
}
returncount;/*返回数对个数*/
}
18.求满足条件的数或数对
求满足条件的数或数对经常采用穷举法。
穷举法的基本思想是:
一一列举各种可能的情况,并判断哪一种是符合要求的解。
这是一种在“没有其他办法情况下的方法”,是一种最“笨”的方法,然而对一些无法用解析法求解的问题往往能奏效,通常采用循环来处理穷举问题。
穷举法一般包含两类,一是找出符合特定条件的一组数(一组解),二是验证定理或猜想。
(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。
下面的程序求所有三3位和4位的Armstrong数。
main()
{inti,j,k,m,t,s,a[5],b[5];
for(m=100;m<10000;m++)
{k=m;j=0;/*k为临时变量,j为位数*/
while(k){a[j++]=k%10;k=k/10;}/*a中存放各位数字*/
for(i=0;i{b[i]=1;/*b中存放各位数字之乘积*/
for(t=0;t