比较三种循环算法
(“WHILE循环算法”、“FOR循环算法”、“REPEAT循环算法”)
以“求1-100之间的所有素数”为例:
REPEAT.PAS (由于其核心算法采用REPEAT UNTIL型循环)
PROGRAM prime(input,output); {求100以内质数} VAR {flagnum用来标示当前数是否为质数} i,num:integer; flagnum:boolean; BEGIN {输出2为质数,下面将不再考虑2} writeln(' 2 is a prime number ...'); {下面开始判断3到100中的数那些是质数} FOR num:=3 TO 100 DO BEGIN {置初值} flagnum:=true; i:=2; REPEAT {用当前数num去除i,如果可以被整除则标记其为非质数} IF num MOD i=0 THEN flagnum:=fal; i:=i+1 UNTIL NOT flagnum OR (i>round(sqrt(num))); {如果当前数num是质数则输出它} IF flagnum=true THEN writeln(num:2,' is a prime number ...') END{FOR} END.
WHILE.PAS (由于其核心算法采用DO WHILE型循环)
PROGRAM prime(input,output); {求1-100之间的素数} VAR {flagnum用来标示当前数是否为素数} i,num:integer; flagnum:boolean; BEGIN {判断2到100中的数那些是质数} FOR num:=2 TO 100 DO BEGIN {置初值} flagnum:=true; i:=2;顾名思义什么意思 {用num除以i到round(sqrt(num)),如果除不尽flagnum保持为真} WHILE flagnum AND (i<=round(sqrt(num))) DO BEGIN IF num MOD i=0 THEN flagnum:=fal; i:=i+1地裂缝 END;{WHILE} {如果flagnum保持为真(即为素数)则输出这个数}儿童咳嗽吃什么药 IF flagnum THEN writeln(num:2,' is a prime number ...') END{FOR} END.
FOR.PAS (由于其核心算法采用FOR型循环)
PROGRAM prime(input,output); {输出1-100中的素数} VAR i,j,count:integer; flag:boolean; BEGIN count:=0; FOR i:=2 TO 100 DO BEGIN {用2到sqrt(i)去除i,看能否除尽} flag:=true; FOR j:=2 to round(sqrt(i)) DO IF i MOD j=0
THEN flag:=fal; IF flag THEN BEGIN write(i:4); count:=count+1; IF count MOD 5=0 THEN writeln END映阶碧草自春色 END END.
下面我简单分析一下这三种核心算法:
首先说说FOR循环的算法,这个算法是书上给出的,它比较“循规蹈矩”一些,采用了植物图2到这个数的平方根作为除数的方法,通过取余数判断当前数是否能被这些除数整除,当然如果可以的话flag将被标记为fal即当前数不是素数。值得一提的是这个算法并没有逐一尝试所有的其他数,只是尝试了2到这个数的平方根。这样做很大程度上提高了程序执行的效率!为了理解其原理这里原引书上的一段话:
用2,3,4,…,根号i去除,如果都除不尽,则i是素数。
这是因为,如果小于等于根号i的数都除不尽i,则大于根号i的数也不能除尽i。
用反证法证明:假设有大于根号i的数j能除尽i,则它的商k必小于根号i,且k能除尽i(其商为j)。这是与原命题(小于等于根号i的数都除不尽i)相矛盾的,假设不成立,原命题得到证明。
但为什么说其“循规蹈矩”呢?那让我们来看看下面两种算法就知道了,REPEAT循环的算法是我最初对这个程序的设计。众所周知REPEAT循环是一种条件型循环,也就是说它的循环是由一个或多个条件来控制的,换句话说我们可以人为干涉它的循环次数。另一方面,判断一个数是否为非素数我们必须把2到这个数的平方根都试一遍么?当然不是,正如大于16的偶数我们只要知道它能被2整除就不用再考虑它能否被4整除的道理一样,只要我们知道一个数已经是非素数了我们就可以大胆地终止这个循环。基于以上两点,我在循环条件中加入了”NOT flagnum”,使循环可以及时退出避免了循环体被无为地执行,提高了程序的执行效率!但采用REPEAT循环有一个致命的缺点,那就是由于其循环条件位于循环体的后边使得循环体被无条件执行了一次,然而正如文章前面提到的这种核心算法将会把2判断为非素数,作为补救的办法只得在第一层循环的外面首先输出2为素数的结果之后再用核心算法判断3-100之间的数,无形中降低了代码的可读性。
那么如何避免REPEAT循环带来的副作用呢?作为改进我使用了WHILE循环的算法,这样就从本质上解决了REPEAT循环的副作用(避免了循环体被无条件执行)。下面我们来看看WHILE循环的算法,其循环条件位于循环体的前边,内容为” flagnum AND (i<=round(sqrt(num)))”,这样既提高了程序的执行效率又避免了可读性下降的弊端。另外
值得注意的是判断2是否为非素数时,由于round(sqrt(2))=1即条件” i<=round(sqrt(num))”为假,所以循环体并没有被执行,故flagnum保持为真即得到2为素数的结果,这与FOR循环的算法有异曲同工之妙。(其实如果循环体被执行的话2仍然会被判断为非素数)
在这里主观地评价一下这三种算法:
从“代码可读性”上来分析REPEAT循环的算法显然没有另外两种循环的算法简洁,而FOR循环的算法要比WHILE循环的算法更容易理解;从“程序执行效率”上来分析采用FOR循环算法的程序执行效率明显低于采用另外两种循环算法的程序,而WHILE循环算法的程序执行效率应当是最高的(所求数的值和范围越大此算法优势越明显)。
小米地瓜粥
红烧羊肉图片 综上所述对于相处的英文这个问题我们可以得出以下结论:
“WHILE循环算法”优于“FOR循环算法”优于“REPEAT循环算法”