算法设计与分析100例子
循环与递归
【例】任给十进制的正整数,请从高位到低位逐位输出各位数字。
循环算法设计
本题目中要求“从高位到低位”逐位输出各位数字,但由于我们并不知道正整数的位数,算法还是“从低位到高位”逐位求出各位数字比较方便。这样就不能边计算边输出,而需要用数组保存计算的结果,最后倒着输出。
# include <stdio.h>
main( )
{
int n,j,i=0,a[16];
printf("请输入一个大于10的整数:\n");
scanf("%d",&n);
while(n>=10){
a[i]=n % 10;
i=i+1;
n=n/10;
}
a[i]=n;
for(j=i;j>=0;j=j-1)
printf("%d",a[j]);
}
递归算法设计
递归的关键在于找出递归方程式和递归终止条件
与f2不同,递归算法是先递归地求n\10的个位数字,然后再求个位数字n的个位数字并输出。这样输出操作是在回溯时完成的。递归停止条件与f2相同为n<10。
# include <stdio.h>
int f(int n)
{
if(n<10)
printf("%d",n);
else{
f(n/10);
printf("%d", n%10);
}
}
main()
{
int n;
printf("请输入一个大于10的整数:\n");
scanf("%d",&n);
f(n);
}
迭代算法
迭代法(Iteration)也称“辗转法”,是一种不断用变量的旧值递推出新值的解决问题的方法。迭代算法一般用于数值计算。迭代法应该是我们早已熟悉的算法策略,程序设计语言课程中所学的累加、累乘都是迭代算法策略的基础应用。
利用迭代算法策略求解问题,设计工作主要有三步:
1)确定迭代模型
2)建立迭代关系式
3)对迭代过程进行控制
【例1】兔子繁殖问题
问题描述:一对兔子从出生后第三个月开始,每月生一对小兔子。小兔子到第三个月又开始生下一代小兔子。假若兔子只生不死,一月份抱来一对刚出生的小兔子,问一年中每个月各有多少只兔子。
问题分析:因一对兔子从出生后第三个月开始每月生一对小兔子,则每月新下小兔子的对儿数(用斜体数字表示)显然由前两个月的小兔子的对儿数决定。则繁殖过程如下:
一月 二月 三月 四月 五月 六月 ……
1 1 1+1=2 2+1=3 3+2=5 5+3=8 ……
#include <stdio.h>
int main( )
{
int i,a=1,b=1,m[10];
//printf("%d%d",a,b);
for(i=1;i<=10;i++)
{
m[i] = a + b;
a=b;
b=m[i];
}
for(i=1;i<=10;i++)
printf("%d ",m[i]);
}
编译结果:
【例2】求两个整数的最大公约数。
数学建模:辗转相除法是根据递推策略设计的。
不妨设两个整数a>b且a除以b商x余c;则a-bx=c,不难看出a、b的最大公约数也是c的约数(一个数能整除等式左边就一定能整除等式的右边),则a、b的最大公约数与b、c的最大公约数相同。同样方法推出b、c的最大公约数与……,直到余数为0时,除数即为所求的最大公约数。
算法设计:循环“不变式”第一次是求a、b相除的余数c,第二次还是求“a”“b” 相除的余数,经a=b,b=c操作,就实现了第二次还是求“a”“b” 相除的余数,这就找到了循环不变式。循环在余数c为0时结束。
例如,计算a = 1071和b = 462的最大公约数的过程如下:从1071中不断减去462直到小于462(可以减2次,即商q0 = 2),余数是147:
1071 = 2 × 462 + 147.
然后从462中不断减去147直到小于147(可以减3次,即q1 = 3),余数是21:
462 = 3 × 147 + 21.
再从147中不断减去21直到小于21(可以减7次,即q2 = 7),没有余数:
147 = 7 × 21 + 0.
此时,余数是0,所以1071和462的最大公约数是21。
#include <stdio.h>
main()
{
int a, b,c,d;
//input(a,b);
printf("请输入两个整数:\n");
scanf("%d%d",&a,&b);
c = a % b;
while(c != 0)
{
a=b;
b=c;
c=a % b;
}
//printf("最大公约数为:%d", b);
d = b;
printf("最大公约数为:%d", d);
}
编译结果: