✅ 操作成功!

迭代法求平方根

发布时间:2023-06-07 作者:admin 来源:文学

迭代法求平方根

迭代法求平方根

夏洛的网好词好句-巧虎下载

2023年2月22日发(作者:二次型的规范型)

迭代法

迭代法也称辗转法,是一种不断用变量的旧值递推新值的过程,跟迭代法相对应

的是直接法(或者称为一次解法),即一次性解决问题。迭代法又分为精确迭代和近

似迭代。“二分法”和“牛顿迭代法”属于近似迭代法.

迭代算法是用计算机解决问题的一种基本方法。它利用计算机运算速度快、适合

做重复性操作的特点,让计算机对一组指令(或一定步骤)进行重复执行,在每次执

行这组指令(或这些步骤)时,都从变量的原值推出它的一个新值。

利用迭代算法解决问题,需要做好以下三个方面的工作:

一、确定迭代变量。在可以用迭代算法解决的问题中,至少存在一个直接或间接

地不断由旧值递推出新值的变量,这个变量就是迭代变量.

二、建立迭代关系式.所谓迭代关系式,指如何从变量的前一个值推出其下一个

值的公式(或关系).迭代关系式的建立是解决迭代问题的关键,通常可以使用递推或倒

推的方法来完成。

三、对迭代过程进行控制.在什么时候结束迭代过程?这是编写迭代程序必须考

虑的问题。不能让迭代过程无休止地重复执行下去.迭代过程的控制通常可分为两种

情况:一种是所需的迭代次数是个确定的值,可以计算出来;另一种是所需的迭代次数

无法确定.对于前一种情况,可以构建一个固定次数的循环来实现对迭代过程的控制;

对于后一种情况,需要进一步分析出用来结束迭代过程的条件。

例1:一个饲养场引进一只刚出生的新品种兔子,这种兔子从出生的下一个月

开始,每月新生一只兔子,新生的兔子也如此繁殖。如果所有的兔子都不死去,问到

第12个月时,该饲养场共有兔子多少只?

分析:这是一个典型的递推问题。我们不妨假设第1个月时兔子的只数为u

1,第2个月时兔子的只数为u2,第3个月时兔子的只数为u3,……根据

题意,“这种兔子从出生的下一个月开始,每月新生一只兔子",则有

u1=1,u2=u1+u1×1=2,u3=u2+u2×1

=4,……

根据这个规律,可以归纳出下面的递推公式:

un=un-1×2(n≥2)

对应un和un-1,定义两个迭代变量y和x,可将上面的递推公式转

换成如下迭代关系:

y=x*2

x=y

让计算机对这个迭代关系重复执行11次,就可以算出第12个月时的兔子数.

参考程序如下:

cls

x=1

fori=2to12

y=x*2

x=y

nexti

printy

end

例2:阿米巴用简单分裂的方式繁殖,它每分裂一次要用3分钟。将若干个阿

米巴放在一个盛满营养参液的容器内,45分钟后容器内充满了阿米巴。已知容器最

多可以装阿米巴220,220个。试问,开始的时候往容器内放了多少个阿米巴?请编

程序算出。

分析:根据题意,阿米巴每3分钟分裂一次,那么从开始的时候将阿米巴放入

容器里面,到45分钟后充满容器,需要分裂45/3=15次。而“容器最多可以装阿米

巴2^20个”,即阿米巴分裂15次以后得到的个数是2^20。题目要求我们计算分

裂之前的阿米巴数,不妨使用倒推的方法,从第15次分裂之后的2^20个,倒推出第

15次分裂之前(即第14次分裂之后)的个数,再进一步倒推出第13次分裂之后、

第12次分裂之后、……第1次分裂之前的个数。

设第1次分裂之前的个数为x0、第1次分裂之后的个数为x1、第2

次分裂之后的个数为x2、……第15次分裂之后的个数为x15,则有

x14=x15/2、x13=x14/2、……xn-1=xn/2(n≥1)

因为第15次分裂之后的个数x15是已知的,如果定义迭代变量为x,则可以

将上面的倒推公式转换成如下的迭代公式:

x=x/2(x的初值为第15次分裂之后的个数2^20)

让这个迭代公式重复执行15次,就可以倒推出第1次分裂之前的阿米巴个数.

因为所需的迭代次数是个确定的值,我们可以使用一个固定次数的循环来实现对迭代

过程的控制。参考程序如下:

cls

x=2^20

fori=1to15

x=x/2

nexti

printx

end

ps:java中幂的算法是(2,20);返回double,稍微注意一下

例3:验证谷角猜想。日本数学家谷角静夫在研究自然数时发现了一个奇怪现

象:对于任意一个自然数n,若n为偶数,则将其除以2;若n为奇数,则将其乘以

3,然后再加1。如此经过有限次运算后,总可以得到自然数1.人们把谷角静夫的

这一发现叫做“谷角猜想”。

要求:编写一个程序,由键盘输入一个自然数n,把n经过有限次运算后,最

终变成自然数1的全过程打印出来。

分析:定义迭代变量为n,按照谷角猜想的内容,可以得到两种情况下的迭代

关系式:当n为偶数时,n=n/2;当n为奇数时,n=n*3+1。用QBASIC语言

把它描述出来就是:

ifn为偶数then

n=n/2

else

n=n*3+1

endif

这就是需要计算机重复执行的迭代过程.这个迭代过程需要重复执行多少次,才

能使迭代变量n最终变成自然数1,这是我们无法计算出来的。因此,还需进一步确

定用来结束迭代过程的条件。仔细分析题目要求,不难看出,对任意给定的一个自然数

n,只要经过有限次运算后,能够得到自然数1,就已经完成了验证工作.因此,用

来结束迭代过程的条件可以定义为:n=1。参考程序如下:

cls

input"Pleaseinputn=”;n

dountiln=1

ifnmod2=0then

rem如果n为偶数,则调用迭代公式n=n/2

n=n/2

print”—”;n;

else

n=n*3+1

print”—";n;

endif

loop

end

迭代法开平方:

#include〈stdio。h〉

#include〈math。h>

voidmain()

{

doublea,x0,x1;

printf(”Inputa:n");

scanf(”%lf”,&a);//为什么在VC6.0中不能写成“scanf("%f”,&a);"?

if(a〈0)

printf(”Error!n”);

else

x0=a/2;

x1=(x0+a/x0)/2;

do

x0=x1;

x1=(x0+a/x0)/2;

}while(fabs(x0—x1)>=1e—6);

}

printf("Result:n");

printf("sqrt(%g)=%gn”,a,x1);

}

求平方根的迭代公式:x1=1/2*(x0+a/x0)。

算法:1.先自定一个初值x0,作为a的平方根值,在我们的程序中取a/2作为a的

初值;利用迭代公式求出一个x1。此值与真正的a的平方根值相比,误差很大。

2。把新求得的x1代入x0中,准备用此新的x0再去求出一个新的x1.

3。利用迭代公式再求出一个新的x1的值,也就是用新的x0又求出一个新的平

方根值x1,此值将更趋近于真正的平方根值。

4。比较前后两次求得的平方根值x0和x1,如果它们的差值小于我们指定的值,

即达到我们要求的精度,则认为x1就是a的平方根值,去执行步骤5;否则执行步骤

2,即循环进行迭代。

迭代法是用于求方程或方程组近似根的一种常用的算法设计方法。设方程为f(x)

=0,用某种数学方法导出等价的形式x=g(x),然后按以下步骤执行:

(1)选一个方程的近似根,赋给变量x0;

(2)将x0的值保存于变量x1,然后计算g(x1),并将结果存于变量x0;

(3)当x0与x1的差的绝对值还小于指定的精度要求时,重复步骤(2)的计算。

若方程有根,并且用上述方法计算出来的近似根序列收敛,则按上述方法求得的

x0就认为是方程的根。上述算法用C程序的形式表示为:

【算法】迭代法求方程的根

{x0=初始近似根;

do{

x1=x0;

x0=g(x1);/*按特定的方程计算新的近似根*/

}while(fabs(x0—x1)〉Epsilon);

printf(“方程的近似根是%fn”,x0);

}

迭代算法也常用于求方程组的根,令

X=(x0,x1,…,xn—1)

设方程组为:

xi=gi(X)(I=0,1,…,n—1)

则求方程组根的迭代算法可描述如下:

【算法】迭代法求方程组的根

{for(i=0;i

x=初始近似根;

do{

for(i=0;i

y=x;

for(i=0;i

x=gi(X);

for(delta=0.0,i=0;i

if(fabs(y-x)〉delta)delta=fabs(y—x);

}while(delta〉Epsilon);

for(i=0;i

printf(“变量x[%d]的近似根是%f”,I,x);

printf(“n");

具体使用迭代法求根时应注意以下两种可能发生的情况:

(1)如果方程无解,算法求出的近似根序列就不会收敛,迭代过程会变成死循

环,因此在使用迭代算法前应先考察方程是否有解,并在程序中对迭代的次数给予限

制;

(2)方程虽然有解,但迭代公式选择不当,或迭代的初始近似根选择不合理,

也会导致迭代失败。

递归

递归是设计和描述算法的一种有力的工具,由于它在复杂算法的描述中被经常采

用,为此在进一步介绍其他算法设计方法之前先讨论它。

能采用递归描述的算法通常有这样的特征:为求解规模为N的问题,设法将它分

解成规模较小的问题,然后从这些小问题的解方便地构造出大问题的解,并且这些规

模较小的问题也能采用同样的分解和综合方法,分解成规模更小的问题,并从这些更

小问题的解构造出规模较大问题的解。特别地,当规模N=1时,能直接得解。

【问题】编写计算斐波那契(Fibonacci)数列的第n项函数fib(n)。

斐波那契数列为:0、1、1、2、3、……,即:

fib(0)=0;

fib(1)=1;

fib(n)=fib(n—1)+fib(n-2)(当n>1时)。

写成递归函数有:

intfib(intn)

{if(n==0)return0;

if(n==1)return1;

if(n>1)returnfib(n-1)+fib(n—2);

}

递归算法的执行过程分递推和回归两个阶段。在递推阶段,把较复杂的问题(规

模为n)的求解推到比原问题简单一些的问题(规模小于n)的求解.例如上例中,求

解fib(n),把它推到求解fib(n—1)和fib(n—2)。也就是说,为计算fib(n),必须

先计算fib(n—1)和fib(n-2),而计算fib(n-1)和fib(n-2),又必须先计算fib(n—

3)和fib(n-4)。依次类推,直至计算fib(1)和fib(0),分别能立即得到结果1和0。

在递推阶段,必须要有终止递归的情况.例如在函数fib中,当n为1和0的情况.

在回归阶段,当获得最简单情况的解后,逐级返回,依次得到稍复杂问题的解,例

如得到fib(1)和fib(0)后,返回得到fib(2)的结果,……,在得到了fib(n—1)和

fib(n-2)的结果后,返回得到fib(n)的结果。

在编写递归函数时要注意,函数中的局部变量和参数知识局限于当前调用层,当

递推进入“简单问题"层时,原来层次上的参数和局部变量便被隐蔽起来。在一系列“简

单问题”层,它们各有自己的参数和局部变量。

由于递归引起一系列的函数调用,并且可能会有一系列的重复计算,递归算法的

执行效率相对较低。当某个递归算法能较方便地转换成递推算法时,通常按递推算法

编写程序。例如上例计算斐波那契数列的第n项的函数fib(n)应采用递推算法,即

从斐波那契数列的前两项出发,逐次由前两项计算出下一项,直至计算出要求的第n

项。

【问题】组合问题

问题描述:找出从自然数1、2、……、n中任取r个数的所有组合。例如n=5,r

=3的所有组合为:(1)5、4、3(2)5、4、2(3)5、4、1

(4)5、3、2(5)5、3、1(6)5、2、1

(7)4、3、2(8)4、3、1(9)4、2、1

(10)3、2、1

分析所列的10个组合,可以采用这样的递归思想来考虑求组合函数的算法.设函

数为voidcomb(intm,intk)为找出从自然数1、2、……、m中任取k个数的所

有组合。当组合的第一个数字选定时,其后的数字是从余下的m—1个数中取k-1数

的组合.这就将求m个数中取k个数的组合问题转化成求m—1个数中取k—1个数的

组合问题。设函数引入工作数组a[]存放求出的组合的数字,约定函数将确定的k

个数字组合的第一个数字放在a[k]中,当一个组合求出后,才将a[]中的一个组合输

出。第一个数可以是m、m—1、……、k,函数将确定组合的第一个数字放入数组后,

有两种可能的选择,因还未去顶组合的其余元素,继续递归去确定;或因已确定了组

合的全部元素,输出这个组合。细节见以下程序中的函数comb.

【程序】

#include

#defineMAXN100

inta[MAXN];

voidcomb(intm,intk)

{inti,j;

for(i=m;i>=k;i—-)

{a[k]=i;

if(k〉1)

comb(i-1,k—1);

else

{for(j=a[0];j>0;j--)

printf(“%4d",a[j]);

printf(“n”);

}

voidmain()

{a[0]=3;

comb(5,3);

【问题】背包问题

问题描述:有不同价值、不同重量的物品n件,求从这n件物品中选取一部分物

品的选择方案,使选中物品的总重量不超过指定的限制重量,但选中物品的价值之和

最大。

设n件物品的重量分别为w0、w1、…、wn-1,物品的价值分别为v0、v1、…、

vn-1。采用递归寻找物品的选择方案。设前面已有了多种选择的方案,并保留了其中总

价值最大的方案于数组option[],该方案的总价值存于变量maxv。当前正在考察新

方案,其物品选择情况保存于数组cop[]。假定当前方案已考虑了前i-1件物品,

现在要考虑第i件物品;当前方案已包含的物品的重量之和为tw;至此,若其余物品

都选择是可能的话,本方案能达到的总价值的期望值为tv。算法引入tv是当一旦当前

方案的总价值的期望值也小于前面方案的总价值maxv时,继续考察当前方案变成无

意义的工作,应终止当前方案,立即去考察下一个方案.因为当方案的总价值不比max

v大时,该方案不会被再考察,这同时保证函数后找到的方案一定会比前面的方案更

好.

对于第i件物品的选择考虑有两种可能:

(1)考虑物品i被选择,这种可能性仅当包含它不会超过方案总重量限制时才是

可行的。选中后,继续递归去考虑其余物品的选择。

(2)考虑物品i不被选择,这种可能性仅当不包含物品i也有可能会找到价值

更大的方案的情况。

按以上思想写出递归算法如下:

try(物品i,当前选择已达到的重量和,本方案可能达到的总价值tv)

{/*考虑物品i包含在当前方案中的可能性*/

if(包含物品i是可以接受的)

{将物品i包含在当前方案中;

if(i

try(i+1,tw+物品i的重量,tv);

else

/*又一个完整方案,因为它比前面的方案好,以它作为最佳方案*/

以当前方案作为临时最佳方案保存;

恢复物品i不包含状态;

}

/*考虑物品i不包含在当前方案中的可能性*/

if(不包含物品i仅是可男考虑的)

if(i

try(i+1,tw,tv—物品i的价值);

else

/*又一个完整方案,因它比前面的方案好,以它作为最佳方案*/

以当前方案作为临时最佳方案保存;

为了理解上述算法,特举以下实例。设有4件物品,它们的重量和价值见表:

物品0123

重量5321

价值4431

并设限制重量为7。则按以上算法,下图表示找解过程。由图知,一旦找到一个

解,算法就进一步找更好的佳。如能判定某个查找分支不会找到更好的解,算法不会

在该分支继续查找,而是立即终止该分支,并去考察下一个分支。

按上述算法编写函数和程序如下:

【程序】

#include

#defineN100

doublelimitW,totV,maxV;

intoption[N],cop[N];

struct{doubleweight;

doublevalue;

}a[N];

intn;

voidfind(inti,doubletw,doubletv)

{intk;

/*考虑物品i包含在当前方案中的可能性*/

if(tw+〈=limitW)

{cop=1;

if(i

else

{for(k=0;k

option[k]=cop[k];

maxv=tv;

cop=0;

}

/*考虑物品i不包含在当前方案中的可能性*/

if(tv—a。value>maxV)

if(i

else

{for(k=0;k

option[k]=cop[k];

maxv=;

}

voidmain()

{intk;

doublew,v;

printf(“输入物品种数n”);

scanf((“%d”,&n);

printf(“输入各物品的重量和价值n”);

for(totv=0.0,k=0;k

{scanf(“%1f%1f”,&w,&v);

a[k]。weight=w;

a[k].value=v;

totV+=V;

printf(“输入限制重量n”);

scanf(“%1f",&limitV);

maxv=0。0;

for(k=0;kfind(0,0。0,totV);

for(k=0;k

if(option[k])printf(“%4d",k+1);

printf(“n总价值为%.2fn”,maxv);

}

作为对比,下面以同样的解题思想,考虑非递归的程序解。为了提高找解速度,

程序不是简单地逐一生成所有候选解,而是从每个物品对候选解的影响来形成值得进

一步考虑的候选解,一个候选解是通过依次考察每个物品形成的。对物品i的考察有

这样几种情况:当该物品被包含在候选解中依旧满足解的总重量的限制,该物品被包

含在候选解中是应该继续考虑的;反之,该物品不应该包括在当前正在形成的候选解

中。同样地,仅当物品不被包括在候选解中,还是有可能找到比目前临时最佳解更好

的候选解时,才去考虑该物品不被包括在候选解中;反之,该物品不包括在当前候选

解中的方案也不应继续考虑.对于任一值得继续考虑的方案,程序就去进一步考虑下一

个物品。

【程序】

#include

#defineN100

doublelimitW;

intcop[N];

structele{doubleweight;

doublevalue;

}a[N];

intk,n;

struct{int;

doubletw;

doubletv;

}twv[N];

voidnext(inti,doubletw,doubletv)

{twv.=1;

twv。tw=tw;

twv。tv=tv;

}

doublefind(structele*a,intn)

{inti,k,f;

doublemaxv,tw,tv,totv;

maxv=0;

for(totv=0。0,k=0;k

totv+=a[k].value;

next(0,0。0,totv);

i=0;

While(i〉=0)

{f=twv。;

tw=twv。tw;

tv=;

switch(f)

{case1:twv.++;

if(tw+a。weight〈=limitW)

if(i

{next(i+1,tw+,tv);

i++;

}

else

{maxv=tv;

for(k=0;k

cop[k]=twv[k]。!=0;

}

break;

case0:i-—;

break;

default:twv。=0;

if(>maxv)

if(i

{next(i+1,tw,tv—a。value);

i++;

}

else

{maxv=;

for(k=0;k

cop[k]=twv[k]。!=0;

break;

}

returnmaxv;

}

voidmain()

{doublemaxv;

printf(“输入物品种数n");

scanf((“%d",&n);

printf(“输入限制重量n”);

scanf(“%1f",&limitW);

printf(“输入各物品的重量和价值n”);

for(k=0;k

scanf(“%1f%1f”,&a[k].weight,&a[k]。value);

maxv=find(a,n);

printf(“n选中的物品为n”);

for(k=0;k

if(option[k])printf(“%4d”,k+1);

printf(“n总价值为%。2fn",maxv);

递归的基本概念和特点

程序调用自身的编程技巧称为递归(recursion)。

一个过程或函数在其定义或说明中又直接或间接调用自身的一种方法,它通常把

一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策

略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的

代码量.递归的能力在于用有限的语句来定义对象的无限集合。用递归思想写出的程

序往往十分简洁易懂。

一般来说,递归需要有边界条件、递归前进段和递归返回段.当边界条件不满足

时,递归前进;当边界条件满足时,递归返回。

注意:

(1)递归就是在过程或函数里调用自身;

(2)在使用递增归策略时,必须有一个明确的递归结束条件,称为递归出口。

👁️ 阅读量:0