循环是程序设计中接触最多code。在进行数值计算的时候,循环往往是用来做累加或累乘的。累加和累乘都有通用的数学模型: Sn=Sn−1+An 和 Tn=Tn−1∗An 。根据这两个数学模型,很容易构造出循环体。
例1:实现一个函数,求1+2+3+…+100的和。
int sum (int n)
{
int s=0;
for(int i=1;i<=n;i++)
s=s+i; //累和,超级简单。
return s;
}
例2:设计求 n! ( n 为正整数)的算法。
long long int fun (int n)
{
long long int f=1;
for(int i=1;i<=n;i++)
f=f*i; //累积,超级简单。
return f;
}
但在编程中,问题往往既涉及累加式又涉及到累乘式。如下面这个题目:
例3:设计求
分析问题:
首先,数学模型为:
其次,累加的对象是一个累积的结果。
所以,初学者很容易想到利用二重循环实现该算法。
int main()
{
int i,j,n,sign=1; //i、j为循环控制变量,n为问题规模
float s=1,t=1; //s累和,t累积
scanf("%d",&n);
for(i=2;i<=n;i++)
{
t=1;
for(j=1;j<=2*i-1;j++)
t*=j;
sign=1;
for(j=1;j<=i+1;j++)
sign=sign*(-1);
s=s+sign/t;
}
printf("sum=%d",s);
}
对以上算法分析,是正确的,但是时间复杂度是
O(n2)
,效率低。因为在内循环中求出
7!
后,再去求
9!
时,没必要再从
1
去累乘到
数学模型2: Sn=Sn−1+(−1)n+1An ; An=An−1∗1/((2∗n−2)(2∗n−1)) 。
int main()
{
int i,n,sign=1; //i为循环控制变量,n为问题规模
float s=1,t=1; //s累和,t累积
scanf("%d",&n);
for(i=2;i<=n;i++)
{
sign=-sign;
t=t*(2*i-2)*(2*i-1);
s=s+sign/t;
}
printf("sum=%d",s);
}
该算法的时间复杂度为 O(n) 。由此可见,构造的循环不变式不同时,他们的效率也不同。对于比较难的问题,可以用“自顶向下”的设计方法,改变数学模型。
例4:设计求 sin(x)=x−x3/3!+x5/5!−x7/7!...... 的算法。
/*sinx=x-x^3/3!+x^5/5-x^7/7!...*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
int i=1,sign=1;
float x,t,fac=1,sinx=0;
scanf("%f",&x);
t=x;
do
{
sinx+=sign*t/fac;
t=t*x*x; //分子t初值为x
fac=fac*(i+1)*(i+2); //分母fac初值为1
i+=2;
sign=-sign;
}while(fabs(t/fac)>=1e-7);
printf("%f\n",sinx);
return 0;
}
算法分析:该算法在
x
的值较小时,计算的结果比较准确。但
参考资料:《算法设计与分析》 第二版 吕国英
转载请注明出处:http://blog.csdn.net/so_geili/article/details/71436430