1、 1 C 语言常用算法归纳 应当掌握的一般算法 一、基本算法: 交换、累加、累乘 二、非数值计算常用经典算法: 穷举、排序(冒泡,选择)、查找(顺序即线性) 三、数值计算常用经典算法: 级数计算(直接、简接即递推)、一元非线性方程求根(牛顿迭代法、二分法)、定积分计算(矩形法、梯形法) 四、其他: 迭代、进制转换、 矩阵转置 、 字符处理(统计、数字串、字母大小写转换、加密等)、整数各数位上数字的获取、辗转相除法求最大公约数(最小公倍数)、求最值、判断素数(各种变形)、数组元素的插入(删除)、二维数组的其他典型问题 (方阵的特点、杨辉三角形) 详细讲解 一、基本算法 1交换(两量交换借助第三者
2、) 例 1、任意读入两个整数,将二者的值交换后输出。 main() int a,b,t; scanf(“%d%d“, printf(“%d,%dn“,a,b); t=a; a=b; b=t; printf(“%d,%dn“,a,b); 2 【解析】程序中加粗部分为算法的核心,如同交换两个杯子里的饮料,必须借助第三个空杯子。 假设输入的值分别为 3、 7,则第一行输出为 3, 7; 第二行输出为 7, 3。 其中 t 为中间变量,起到 “空杯子 ”的作用。 注意:三句赋值语句赋值号左右的各量之间的关系! 【应用】 例 2、任意读入三个整数,然后按从小到大的顺序输出。 main() int a,b
3、,c,t; scanf(“%d%d%d“, /*以下两个 if 语句使得 a 中存放的数最小 */ if(ab) t=a; a=b; b=t; if(ac) t=a; a=c; c=t; /*以下 if 语句使得 b 中存放的数次小 */ if(bc) t=b; b=c; c=t; printf(“%d,%d,%dn“,a,b,c); 2累加 累加算法的要领是形如 “s=s+A”的累加式,此式必须出现在循环中才能被反复执行,从而实现累加功能。 “A”通常是有规律变化的表达式, s 在进入循环前必须获得合适的初值,通常为 0。 例 1、求 1+2+3+100 的和。 main() int i,s
4、; s=0; i=1; while(iai+1) t=ai;ai=ai+1;ai+1=t; for(i=0;ian-2) an-1=x ; /*比最后一个数还大就往最后一个元素中存放 */ else /*查找待插位置 */ j=0; while( jaj) j+; for(k=n-2; k=j; k- -) /*从最后一个数开始直到待插位置上的数依次后移一位 */ ak+1=ak; aj=x; /*插入待插数 */ for(j=0;j=i;k-) ak+1=ak; ai=x; /*插入待插数 */ for(i=0;i=m main() float x,eps; scanf(“%f%f“, pr
5、intf(“n%f,%fn“,x,g(x,eps); float g(float x,float eps) int n=1;float s,t; s=1; t=1; do t=t*x/(2*n); s=s+(n*n+1)*t; /*加波浪线的部分为直接法描述部分, t 为递推法描述部分 */ n+; while(fabs(t)eps); return s; 2一元非线性方程求根 ( 1) 牛顿迭代法 牛顿迭代法又称牛顿切线法:先任意设定一个与真实的根接近的值 x0 作为第一次近似根,由 x0 求出 f(x0),过 (x0, f(x0)点做 f(x)的切线,交 x 轴于 x1,把它作为第二次近似
6、根,再由 x1 求出 f(x1),过 (x1, f(x1)点做 f(x)的切线,交 x 轴于 x2, 如此继续下去,直到足够接近(比如 |x- x0|=1e-5); printf (“%fn“,x); ( 2) 二分法 算法要领是:先指定一个区间 x1, x2,如果函数 f(x)在此区间是单调变化的,则可以根据 f(x1)和 f(x2)是否同号来确定方程 f(x)=0在区间 x1, x2内是否有一个实根;如果 f(x1)和 f(x2)同号,则 f(x) 在区间 x1, x2内无实根,要重新改变 x1 和 x2 的值。当确定 f(x) 在区间 x1, x2内有一个实根后,可采取二分法将 x1,
7、x2一分为二,再判 断在哪一个小区间中有实根。如此不断进行下去,直到小区间足够小为止。 具体算法如下: ( 1)输入 x1 和 x2 的值。 ( 2)求 f(x1)和 f(x2)。 ( 3)如果 f(x1)和 f(x2)同号说明在 x1, x2 内无实根,返回步骤( 1),重新输入 x1 和x2 的值;若 f(x1)和 f(x2)不同号,则在区间 x1, x2内必有一个实根,执行步骤( 4)。 ( 4)求 x1 和 x2 的中点: x0=( x1+ x2) /2。 ( 5)求 f(x0)。 ( 6)判断 f(x0)与 f(x1)是否同号。 如果同号,则应在 x0, x2中寻找根, 此时 x1
8、已不起作用,用 x0 代替 x1,用 f(x0)代替 f(x1)。 如果不同号,则应在 x1, x0中寻找根,此时 x2 已不起作用,用 x0 代替 x2,用 f(x0)代替 f(x2)。 ( 7)判断 f(x0)的绝对值是否小于某一指定的值(例如 10-5)。若不小于 10-5,则返回步骤( 4)重复执行步骤( 4)、( 5)、( 6);否则执行步骤( 8)。 11 ( 8)输出 x0 的值,它就是所求出的近似根。 例如,用二分法求方程 2x3-4x2+3x-6=0 在 (-10, 10)之间的根。 #include “math.h“ main() float x1,x2,x0,fx1,fx
9、2,fx0; do printf(“Enter x1 scanf(“%f%f“, fx1=2*x1*x1*x1-4*x1*x1+3*x1-6; fx2=2*x2*x2*x2-4*x2*x2+3*x2-6; while(fx1*fx20); do x0=(x1+x2)/2; fx0=2*x0*x0*x0-4*x0*x0+3*x0-6; if(fx0*fx1)1e-5); printf(“%fn“,x0); 3梯形法计算定积分 定积分 的几何意义是求曲线 y=f(x)、 x=a、 x=b 以及 x 轴所围成的面积。 可以近似地把面积视为若干小的梯形面积之和。例如,把区间 a, b分成 n 个长度相
10、等的小区间,每个小区间的长度为 h=(b-a)/n,第 i 个小梯形的面积为 f(a+(i-1)h)+f(a+ih)h/2,将 n 个小梯形面积加起来就得到定积分的近似值: 根据以上分析,给出 “梯形法 ”求定积分的 N-S 结构图: 输入区间端点: a, b 输入等分数 n h=(b-a)/2, s=0 i 从 1 到 n si=(f(a+(i-1)*h)+f(a+i*h)*h/2 s=s+si 输出 s 12 上述程序的几何意义比较明显,容易理解。但是其中存在重复计算,每次循环都要计算小梯形的上、下底。其实,前一个小梯形的下底就是后一个小梯形的上底,完全不必重复计算。为此做出如下改进: 矩
11、形法求定积分则更简单,就是将等分出来的图形当作矩形,而不是梯形。 例如:求定积分 的值。等分数 n=1000。 #include “math.h“ float DJF(float a,float b) float t,h; int n,i; float HSZ(float x); n=1000; h=fabs(a-b)/n; t=(HSZ(a)+HSZ(b)/2; for(i=1;i=1;day-) peach=(peach+1)*2; printf(“The first day:%dn“,peach); 又如,用迭代法求 x= 的根。 求平方根的迭代 公式是: xn+1=0.5(xn+a/
12、xn ) 算法 ( 1)设定一个初值 x0。 ( 2)用上述公式求出下一个值 x1。 ( 3)再将 x1 代入上述公式,求出下一个值 x2。 ( 4)如此继续下去,直到前后两次求出的 x 值( xn+1 和 xn)满足以下关系: | xn+1- xn|=1e-5); printf(“%fn“,x1); 2进制转换 ( 1)十进制数转换为其他进制数 14 一个十进制正整数 m 转换成 r 进制数的思路是,将 m 不断除以 r 取余数,直到商为 0 时止,以反序输出余数序列即得到结果。 注意,转换得到的不是数值,而是数字字符串或数字串。 例如,任意读入一个十进制正整数,将其转换成二至十六任意进制的
13、字符串。 void tran(int m,int r,char str,int *n) char sb=“0123456789ABCDEF“; int i=0,g; do g=m%r; stri=sbg; m=m/r; i+; while(m!=0); *n=i; main() int x,r0; /*r0 为进制基数 */ int i,n; /*n 中存放生成序列的元素个数 */ char a50; scanf(“%d%d“, if(x0i-) printf(“%c“,ai); printf(“n“); else exit(0); ( 2)其他进制数转换为十进制数 其他进制整数转换为十进制整
14、数的要领是: “按权展开 ”,例如,有二进制数 101011,则其十进制形式为 125+024+123+022+121+120=43。若 r 进制数 ana2a1 ( n 位数)转换成十进制数,方法是 anr n-1+a2r1+a1r0 。 注意:其他进 制数只能以字符串形式输入。 例 1、任意读入一个二至十六进制数(字符串),转换成十进制数后输出。 #include “string.h“ #include “ctype.h“ main() char x20; int r,d; gets(x); /*输入一个 r 进制整数序列 */ scanf(“%d“, /*输入待处理的进制基数 2-16*
15、/ d=Tran(x,r); printf(“%s=%dn“,x,d); 15 int Tran(char *p,int r) int d,i,cr; char fh,c; d=0; fh=*p; if(fh=-) p+; for(i=0;i=A) cr=toupper(c)-A+10; else cr=c-0; d=d*r+cr; if(fh=-) d=-d; return(d); 3矩阵转置 矩阵转置的算法要领是:将一个 m 行 n 列矩阵(即 mn 矩阵)的每一行转置成另一个 nm矩阵的相应列。 例 1、将以下 23 矩阵转置后输出。 即将 1 2 3 转置成 1 4 4 5 6 2 5
16、 3 6 main() int a23,b32,i,j,k=1; for(i=0;i=xj-) printf(“%d “,aj); printf(“n“); 6辗转相除法求两个正整数的最大公约数 该算法的要领是:假设两个正整数为 a 和 b,先求出前者除以后者的余数,存放到变量 r中,若 r 不为 0,则将 b 的值得赋给 a,将 r 的值得赋给 b;再求出 a 除以 b 的余数,仍 然存放到变量 r 中 如此反复,直至 r 为 0 时终止,此时 b 中存放的即为原来两数的最大公约数。 例 1、任意读入两个正整数,求出它们的最大公约数。 法一 :用 while 循环时,最大公约数存放于 b 中 main() int a,b,r; do scanf(“%d%d“, 18 while(amax) max=ai; else if(ai #include main( ) int k,j,a101; clrscr(); /*清屏函数 */ for(k=2;k=0;j-) printf(“ “); /*输出时每行前导空格递减 */ for(j=0;j=i;j+) printf(“%4d“,aij); printf(“n“);