一、简单数值类算法

此类问题都要使用循环,要注意根据问题确定循环变量的初值、终值或结束条件,更要注意用来表示计数、和、阶乘的变量的初值。

1、  求阶乘     

下列程序用于求n的阶乘.在累乘之前,

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

long func(int n)

{

  int i;

  long t=1;

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

    t*=i;

  return t;

}

 

printf("\n");

}

2、求回文数的函数

int  hws(int  a)

{int c=0;

 while(a>0)

 { c=c*10+a%10;    

   a/=10;

}

 return(c);

}

3、  整数拆分问题:把一个整数各个位上的数字存到数组中
(1)确定3位数                                  

(2)不确定数字位数,

利用数组存储数字           

利用变量存储数字              

数组定义足够大

int  split(int  n,  int  a[10 ])

{int  i;

 for(i=0;n!=0; i++)

  { a[i]=n%10;

    n=n/10;

  }

return  i;  /*返回数字个数*/

}

#define  N   3  

a=n/100;

b=n/10%10;

c=n%10;
viod split(int  n,  int  a[ ])
{int i;

 for(i=N-1;n!=0; i--)

  { a[i]=n%10;

    n=n/10;

  }

}

4、求整数的因子之和

long  factor(int  n)
{int i;
long   sum=0;
for(i=1;i<=n;i++)
if(n%i= =0)
sum+=i;return sum;
}

注意:因子包括1和自身。

二、求两个整数的最大公约数、最小公倍数

分析:求最大公约数的算法为辗转相除法。(最小公倍数=两个整数之积/最大公约数)

求最大公约数的算法步骤:

(1) 对于已知两数m,n,使得m>n;

(2) m除以n得余数r;

(3) 若r=0,则n为求得的最大公约数,算法结束;否则执行(4);

(4) m←n,n←r,再重复执行(2)。

例如: 求 m=14 ,n=6 的最大公约数. m n r

14 %6= 2
6 %2= 0
void main()
{ int nm,r,n,m,t;
printf("please input two numbers:\n");
scanf("%d,%d",&m,&n);
nm=n*m;
if (m<n)
{ t=n; n=m; m=t; }
r=m%n;
while (r!=0)
{ m=n; n=r; r=m%n; }
printf("最大公约数:%d\n",n);
printf("最小公倍数:%d\n",nm/n);
}

将其写成一函数,返回最大公约数。

int gcd(int m,int n)
{  int t,r;
if(m<n) { t=m;m=n;n=t; }
r=m%n;
while(r!=0)
{ m=n;   n=r;   r=m%n;   }
return n;
}

如果求最小公倍数,其函数形式稍作调整:

int gcd(int m,int n)
{  int a=m, b=n;
int t,r;
if(m<n) { t=m;m=n;n=t; }
r=m%n;
while(r!=0)
{ m=n;   n=r;   r=m%n;   }
return (a*b)/n;
}

三、判断素数

只能被1和本身整除的正整数称为素数。

基本思想:在判断数m是否为素数时,首先把m作为被除数,将2—sqrt(m)的所有数字依次作为除数,去除m,只要有一个数能将m整除,则m不是素数;否则,如果都除不尽,则m就是素数。(可用以下程序段实现)

#include  <math.h>
void main()
{ int m,i,k;
printf("please input a number:\n");
scanf("%d",&m);
k=sqrt(m);           /使用此函数一定要加头文件#include  <math.h>/
for(i=2;i<=k;i++)
if(m%i==0) break;
if(i>k)
printf("该数是素数");
else
printf("该数不是素数");
}

将其写成一函数,若为素数返回1,不是则返回0

int prime( int m)
{int i,k;
if(m==1)  return 0;
for(i=2;i<=k-1;i++)
if(m%i==0) return 0;
return 1;
}

四、求最值

例如求最小值算法思想:

定义变量min用于存放当前所有找到的最小数,a为已知数组。算法步骤如下:

1)在min中存放第1个数,比较从数组中的第二个元素开始。

2)数组a中每个元素依次与min中的数组相比,小者放入min中。

3)比较完数组的最后一个元素,算法结束。Min中数为所求。

程序如下:

求最大值:

max=a[0];

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

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

int minvalue(int a[],int n) {int i,min;

min=a[0];

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

if(a[i]<min)  min=a[i];

return min;

}

main()

{ int a[10]={12,45,7,8,96,4,10,48,2,46},i,min;

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

printf(“%3d”,a[i]);

printf(“\n”); min=minvalue(a,10); printf(“the result is:%d”, min); }

五、排序问题

1.选择法排序(升序)

基本思想:

1)对有n个数的序列(存放在数组a(n)中),从中选出最小的数,与第1个数交换位置;

2)除第1 个数外,其余n-1个数中选最小的数,与第2个数交换位置;

3)依次类推,选择了n-1次后,这个数列已按升序排列。

自定义函数形式

void sort(int a[], int n)
{ int i,j,imin,s;
for(i=0;i<n-1;i++)
{ imin=i;
for(j=i+1;j<n;j++)
if(a[imin]>a[j]) imin=j;
if(i!=imin)
{s=a[i]; a[i]=a[imin]; a[imin]=s; }
}
}

程序代码如下:

void main()
{ int i,j,imin,s,a[10];
printf("\n input 10 numbers:\n");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
for(i=0;i<9;i++)
{ imin=i;
for(j=i+1;j<10;j++)
if(a[imin]>a[j]) imin=j;
if(i!=imin)
{s=a[i]; a[i]=a[imin]; a[imin]=s; }
printf("%d\n",a[i]);
}
}

2.冒泡法排序(升序)

基本思想:(将相邻两个数比较,小的调到前头)

1)有n个数(存放在数组a(n)中),第一趟将每相邻两个数比较,小的调到前头,经n-1次两两相邻比较后,最大的数已“沉底”,放在最后一个位置,小数上升“浮起”;

2)第二趟对余下的n-1个数(最大的数已“沉底”)按上法比较,经n-2次两两相邻比较后得次大的数;

3)依次类推,n个数共进行n-1趟比较,在第j趟中要进行n-j次两两比较。

程序段如下

void main()

自定义函数形式:

void sort(int a[], int n)
{ int i,j,t;
for(j=0;j<=8;j++)
for(i=0;i<9-j;i++)
if(a[i]>a[i+1])
{t=a[i];a[i]=a[i+1];a[i+1]=t;}
}
{ int a[10];
int i,j,t;
printf("input 10 numbers\n");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
printf("\n");
for(j=0;j<=8;j++)
for(i=0;i<9-j;i++)
if(a[i]>a[i+1])
{t=a[i];a[i]=a[i+1];a[i+1]=t;}
printf("the sorted numbers:\n");
for(i=0;i<10;i++)
printf("%d\n",a[i]);
}

3.合并法排序(将两个有序数组A、B合并成另一个有序的数组C,升序)

基本思想:

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

2)取小的元素所在数组的下一个元素与另一数组中上次比较后较大的元素比较,重复上述比较过程,直到某个数组被先排完;

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

程序段如下:

void main()
{ int a[10],b[10],c[20],i,ia,ib,ic;
printf("please input the first array:\n");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
for(i=0;i<10;i++)
scanf("%d",&b[i]);
printf("\n");
ia=0;ib=0;ic=0;
while(ia<10&&ib<10)
{ if(a[ia]<b[ib])
{ c[ic]=a[ia];ia++;}
else
{ c[ic]=b[ib];ib++;}
ic++;
}
while(ia<=9)
{ c[ic]=a[ia];
ia++;ic++;
}
while(ib<=9)
{ c[ic]=b[ib];
ib++;ic++;
}
for(i=0;i<20;i++)
printf("%d\n",c[i]);
}

六、查找问题

1.①顺序查找法(在一列数中查找某数x)

思考:将上面程序改写一查找函数Find,若找到则返回下标值,找不到返回-1

②基本思想:一列数放在数组a[1]---a[n]中,待查找的关键值为key,把key与a数组中的元素从头到尾一一进行比较查找,若相同,查找成功,若找不到,则查找失败。(查找子过程如下。index:存放找到元素的下标。)

采用另外一种方法自定义函数,若找到则返回下标值,找不到返回-1:

int seek(int a[],int n, int x)
{  int p=0;
while(x!=a[p]&&p<n)
p++;
if(p>=n) return -1;
else return p;
}
void main()
{ int a[10],index,x,i;
printf("please input the array:\n");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
printf("please input the number you want find:\n");
scanf("%d",&x);
printf("\n");
index=-1;
for(i=0;i<10;i++)
if(x==a[i])
{ index=i; break;
}
if(index==-1)
printf("the number is not found!\n");
else
printf("the number is found the no%d!\n",index);
}

2.折半查找法(只能对有序数列进行查找)

基本思想:设n个有序数(从小到大)存放在数组a[1]----a[n]中,要查找的数为x。用变量bot、top、mid 分别表示查找数据范围的底部(数组下界)、顶部(数组的上界)和中间,mid=(top+bot)/2,折半查找的算法如下:

(1)x=a(mid),则已找到退出循环,否则进行下面的判断;

(2)x<a(mid),x必定落在bot和mid-1的范围之内,即top=mid-1;

(3)x>a(mid),x必定落在mid+1和top的范围之内,即bot=mid+1;

(4)在确定了新的查找范围后,重复进行以上比较,直到找到或者bot>=top。

将上面的算法写成如下程序:

void main()
{
int a[10],mid,bot,top,x,i,find;
printf("please input the array:\n");
for(i=0;i<10;i++)
scanf("%d",&a[i]);
printf("please input the number you want find:\n");
scanf("%d",&x);
printf("\n");
bot=0;top=9;find=0;
while(bot<top&&find==0)
{ mid=(top+bot)/2;
if(x==a[mid])   {find=1;break;}
else if(x<a[mid]) top=mid-1;
else bot=mid+1;
}
if (find==1)
printf("the number is found the no%d!\n",mid);
else
printf("the number is not found!\n");
}

七、插入法

把一个数插到有序数列中,插入后数列仍然有序

基本思想:n个有序数(从小到大)存放在数组a(1)—a(n)中,要插入的数x。首先确定x插在数组中的位置P;(可由以下语句实现)

#define N 10
void insert(int a[],int x)
{ int p, i;
p=0;
while(x>a[p]&&p<N)
p++;
for(i=N; i>p; i--)
a[i]=a[i-1];
a[p]=x;
}
main()
{ int a[N+1]={1,3,4,7,8,11,13,18,56,78}, x, i;
for(i=0; i<N; i++) printf("%d,", a[i]);
printf("\nInput x:");
scanf("%d", &x);
insert(a, x);
for(i=0; i<=N; i++) printf("%d,", a[i]);
printf("\n");
}

八、矩阵(二维数组)运算

(1)矩阵的加、减运算

C(i,j)=a(i,j)+b(i,j) 加法

C(i,j)=a(i,j)-b(i,j) 减法

(2)矩阵相乘

(矩阵A有ML个元素,矩阵B有LN个元素,则矩阵C=AB有MN个元素)。矩阵C中任一元素 (i=1,2,…,m; j=1,2,…,n)

#define M 2
#define L 4
#define N 3
void mv(int a[M][L], int b[L][N], int c[M][N])
{ int i, j, k;
for(i=0; i<M; i++)
for(j=0; j<N; j++)
{ c[i][j]=0;
for(k=0; k<L; k++)
c[i][j]+=a[i][k]*b[k][j];
}
}
main()
{ int a[M][L]={{1,2,3,4},{1,1,1,1}};
int b[L][N]={{1,1,1},{1,2,1},{2,2,1},{2,3,1}}, c[M][N];
int i, j;
mv(a,b,c);
for(i=0; i<M; i++)
{ for(j=0; j<N; j++)
printf("%4d", c[i][j]);
printf("\n");
}
}

(3)矩阵转置

算法思想:指将矩阵中元素的行下标和列下标交换,形成的新矩阵就是原矩阵的转置矩阵。

在转置方阵时须注意,只用遍历方阵的上三角形(或下三角形),将其中的元素和其对应元素进行一次交换即可。如果是遍历整个方阵,并将每个元素都和它对应元素交换,结果会发现方阵没有发生变化,原因是每个元素都做了两次交换,最终又换回到原来的位置上。

例:有二维数组a(5,5),要对它实现转置,可用下面两种方式:

#define N 3
void ch1(int a[N][N])    /只遍历方阵的上三角形/
{ int i, j, t;
for(i=0; i<N; i++)
for(j=i+1; j<N; j++)
{ t=a[i][j];
a[i][j]=a[j][i];
a[j][i]=t;
}
}
void ch2(int a[N][N])   /只遍历方阵的下三角形/
{ int i, j, t;
for(i=1; i<N; i++)
for(j= 0; j<i; j++)
{ t=a[i][j];
a[i][j]=a[j][i];
a[j][i]=t;
}
}
main()
{ int a[N][N]={{1,2,3},{4,5,6},{7,8,9}}, i, j;
ch1(a); /或ch2(a);/
for(i=0; i<N; i++)
{ for(j=0; j<N; j++)
printf("%4d", a[i][j]);
printf("\n");
}
}

(4)求二维数组中最小元素及其所在的行和列

基本思路同一维数组,可用下面程序段实现(以二维数组a[3][4]为例):

‘变量minx中存放最小值,row,column存放最小值所在行列号

#define N 4
#define M 3
void min(int a[M][N])
{ int min, row, column, i, j;
min=a[0][0];
row=0;
column=0;
for(i=0; i<M; i++)
for(j=0; j<N; j++)
if(a[i][j]<min)
{ min=a[i][j];
row=i;
column=j;
}
printf("Min=%d\nAt Row%d,Column%d\n", min, row, column);
}
main()
{ int a[M][N]={{1,23,45,-5},{5,6,-7,6},{0,33,8,15}};
min(a);
}

九、迭代法

算法思想:对于一个问题的求解x,可由给定的一个初值x0,根据某一迭代公式得到一个新的值x1,这个新值x1比初值x0更接近要求的值x;再以新值作为初值,即:x1→x0,重新按原来的方法求x1,重复这一过和直到|x1-x0|<ε(某一给定的精度)。此时可将x1作为问题的解。

例:用迭代法求某个数的平方根。 已知求平方根的迭代公式为:

#include<math.h>
float fsqrt(float a)
{ float x0, x1;
x1=a/2;
do{
x0=x1;
x1=0.5*(x0+a/x0);
}while(fabs(x1-x0)>0.00001);
return(x1);
}
main()
{ float a;
scanf("%f", &a);
printf("genhao =%f\n", fsqrt(a));
}

十、数制转换

将一个十进制整数m转换成 →r(2-16)进制字符串。

方法:将m不断除 r 取余数,直到商为零,以反序得到结果。下面写出一转换函数,参数idec为十进制数,ibase为要转换成数的基(如二进制的基是2,八进制的基是8等),函数输出结果是字符串。

char *trdec(int idec, int ibase)
{ char strdr[20], t;
int i, idr, p=0;
while(idec!=0)
{ idr=idec % ibase;
if(idr>=10)
strdr[p++]=idr-10+65;
else
strdr[p++]=idr+48;
idec/=ibase;
}
main()
{ int x, d;
scanf("%d%d", &x, &d);
printf("%s\n", trdec(x,d));
}
for(i=0; i<p/2; i++)
{ t=strdr[i];
strdr[i]=strdr[p-i-1];
strdr[p-i-1]=t;
}
strdr[p]=’\0’;
return(strdr);
}

十一、字符串的一般处理

1.简单加密和解密

加密的思想是: 将每个字母C加(或减)一序数K,即用它后的第K个字母代替,变换式公式: c=c+k

例如序数k为5,这时 A→ F, a→f,B→?G… 当加序数后的字母超过Z或z则 c=c+k -26

例如:You are good→ Dtz fwj ltti

解密为加密的逆过程

将每个字母C减(或加)一序数K,即 c=c-k,

例如序数k为5,这时 Z→U,z→u,Y→T… 当加序数后的字母小于A或a则 c=c-k +26

下段程序是加密处理:

#include<stdio.h>
char *jiami(char stri[])
{ int i=0;
char strp[50],ia;
while(stri[i]!=’\0’)
{  if(stri[i]>=’A’&&stri[i]<=’Z’)
{ ia=stri[i]+5;
if (ia>’Z’) ia-=26;
}
else if(stri[i]>=’a’&&stri[i]<=’z’)
{ ia=stri[i]+5;
if (ia>’z’) ia-=26;
}
else ia=stri[i];
strp[i++]=ia;
}
strp[i]=’\0’;
return(strp);
}
main()
{ char s[50];
gets(s);
printf("%s\n", jiami(s));
}

2.统计文本单词的个数

输入一行字符,统计其中有多少个单词,单词之间用格分隔开。

算法思路:

(1)从文本(字符串)的左边开始,取出一个字符;设逻辑量word表示所取字符是否是单词内的字符,初值设为0

(2)若所取字符不是“空格”,“逗号”,“分号”或“感叹号”等单词的分隔符,再判断word是否为1,若word不为1则表是新单词的开始,让单词数num = num +1,让word =1;

(3)若所取字符是“空格”,“逗号”,“分号”或“感叹号”等单词的分隔符, 则表示字符不是单词内字符,让word=0;

(4) 再依次取下一个字符,重得(2)(3)直到文本结束。

下面程序段是字符串string中包含的单词数

#include "stdio.h"
main()
{char c,string[80];
int i,num=0,word=0;
gets(string);
for(i=0;(c=string[i])!='\0';i++)
if(c==' ') word=0;
else if(word==0)
{ word=1;
num++;}
printf("There are %d word in the line.\n",num);
}

3、连接两个字符串

void fun(char p1[],char p2[])
{
int i,j;
for(i=0;p1[i];i++) ;     也可写成 for(i=0;p1[i]!=’\0’;i++) ;
for(j=0;p2[j];j++)
p1[i++]=p2[j];
p1[i]=’\0’;
}

注:字符串还有查找字符出现次数,插入、删除字符等。

十二、穷举法

穷举法(又称“枚举法”)的基本思想是:一一列举各种可能的情况,并判断哪一种可能是符合要求的解,这是一种“在没有其它办法的情况的方法”,是一种最“笨”的方法,然而对一些无法用解析法求 解的问题往往能奏效,通常采用循环来处理穷举问题。

例: 将一张面值为100元的人民币等值换成100张5元、1元和0.5元的零钞,要求每种零钞不少于1张,问有哪几种组合?

main()
{ int i, j, k;
printf(" 5元 1元 5角\n");
for(i=1; i<=20; i++)
for(j=1; j<=100-i; j++)
{ k=100-i-j;
if(5i+1j+0.5*k==100)
printf(" %3d %3d %3d\n", i, j, k);
}
}

十三、递归算法

用自身的结构来描述自身,称递归

递归处理一般用栈来实现,每调用一次自身,把当前参数压栈,直到递归结束条件;然后从栈中弹出当前参数,直到栈空。

递归条件:(1)递归结束条件及结束时的值;(2)能用递归形式表示,且递归向终止条件发展。

例:编fac(n)=n! 的递归函数

int fac(int n)
{ if(n==1)
return(1);
else
return(n*fac(n-1));
}
main()
{ int n;
scanf("%d", &n);
printf("n!=%d\n", fac(n));
}

十四、将数组元素逆置

算法思想:

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

此算法可用于整型、字符型等不同类型的数组。

exchange(int a[], int n)
{  int i,t;
for(i=0;i<n/2;i++)
{
t=a[i]; a[i]=a[n-i-1];a[n-i-1]=t;    }    }
t=a[i]; a[i]=a[n-i-1];a[n-i-1]=t;    }    }