c语言编程问题,循环+递归

Python010

c语言编程问题,循环+递归,第1张

int count = 0

void a( void )

{

�0�2count++

�0�2if ( count <100 )

�0�2a() // 如果count<100, 调用自己。一直到100就停止!不过递归多了耗尽堆栈会崩溃!

}

递归算法:是一种直接或者间接地调用自身的算法。在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易于理解。

递归算法的特点

递归过程一般通过函数或子过程来实现。

递归算法:在函数或子过程的内部,直接或者间接地调用自己的算法。

递归算法的实质:是把问题转化为规模缩小了的同类问题的子问题。然后递归调用函数(或过程)来表示问题的解。

递归算法解决问题的特点:

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

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

(3) 递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。

(4) 在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。所以一般不提倡用递归算法设计程序。

递归算法所体现的“重复”一般有三个要求:

一是每次调用在规模上都有所缩小(通常是减半);

二是相邻两次重复之间有紧密的联系,前一次要为后一次做准备(通常前一次的输出就作为后一次的输入);

三是在问题的规模极小时必须用直接给出解答而不再进行递归调用,因而每次递归调用都是有条件的(以规模未达到直接解答的大小为条件),无条件递归调用将会成为死循环而不能正常结束。

例子如下:

描述:把一个整数按n(2<=n<=20)进制表示出来,并保存在给定字符串中。比如121用二进制表示得到结果为:“1111001”。

参数说明:s: 保存转换后得到的结果。

n: 待转换的整数。

b: n进制(2<=n<=20)

void

numbconv(char *s, int n, int b)

{

int len

if(n == 0) {

strcpy(s, "")

return

}

/* figure out first n-1 digits */

numbconv(s, n/b, b)

/* add last digit */

len = strlen(s)

s[len] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[n%b]

s[len+1] = '\0'

}

void

main(void)

{

char s[20]

int i, base

FILE *fin, *fout

fin = fopen("palsquare.in", "r")

fout = fopen("palsquare.out", "w")

assert(fin != NULL &&fout != NULL)

fscanf(fin, "%d", &base)

/*PLS set START and END*/

for(i=STARTi <= ENDi++) {

numbconv(s, i*i, base)

fprintf(fout, "%s\n", s)

}

exit(0)

}

递归算法简析(PASCAL语言)

递归是计算机科学的一个重要概念,递归的方法是程序设计中有效的方法,采用递归编写

程序能是程序变得简洁和清晰.

一 递归的概念

1.概念

一个过程(或函数)直接或间接调用自己本身,这种过程(或函数)叫递归过程(或函数).

如:

procedure a

begin

.

.

.

a

.

.

.

end

这种方式是直接调用.

又如:

procedure bprocedure c

begin begin�0�2

. .

. .

. .

cb

. .

. .

. .

endend

这种方式是间接调用.

例1计算n!可用递归公式如下:

1 当 n=0 时�0�2

fac(n)={n*fac(n-1) 当n>0时

可编写程序如下:

program fac2

var

n:integer

function fac(n:integer):real

begin

if n=0 then fac:=1 else fac:=n*fac(n-1)

end

begin

write('n=')readln(n)

writeln('fac(',n,')=',fac(n):6:0)

end.

例2 楼梯有n阶台阶,上楼可以一步上1阶,也可以一步上2阶,编一程序计算共有多少种不同的走法.

设n阶台阶的走法数为f(n)

显然有

1 n=1�0�2

f(n)={

f(n-1)+f(n-2) n>2

可编程序如下:

program louti

var n:integer

function f(x:integer):integer

begin

if x=1 then f:=1 else

if x=2 then f:=2 else f:=f(x-1)+f(x-2)

end

begin

write('n=')read(n)

writeln('f(',n,')=',f(n))

end.

二,如何设计递归算法

1.确定递归公式

2.确定边界(终了)条件

三,典型例题

例3 梵塔问题

如图:已知有三根针分别用1,2,3表示,在一号针中从小放n个盘子,现要求把所有的盘子

从1针全部移到3针,移动规则是:使用2针作为过度针,每次只移动一块盘子,且每根针上

不能出现大盘压小盘.找出移动次数最小的方案.

程序如下:

program fanta

var

n:integer

procedure move(n,a,b,c:integer)

begin

if n=1 then writeln(a,'--->',c)

else begin

move(n-1,a,c,b)

writeln(a,'--->',c)

move(n-1,b,a,c)

end

end

begin

write('Enter n=')

read(n)

move(n,1,2,3)

end.

例4 快速排序

快速排序的思想是:先从数据序列中选一个元素,并将序列中所有比该元素小的元素都放到它的右边或左边,再对左右两边分别用同样的方法处之直到每一个待处理的序列的长度为1, 处理结束.

程序如下:

program kspv

const n=7

type

arr=array[1..n] of integer

var

a:arr

i:integer

procedure quicksort(var b:arrs,t:integer)

var i,j,x,t1:integer

begin

i:=sj:=tx:=b

repeat

while (b[j]>=x) and (j>i) do j:=j-1

if j>i then begin t1:=bb:=b[j]b[j]:=t1end

while (b<=x) and (i<j) do i:=i+1

if i<j then begin t1:=b[j]b[j]:=bb:=t1end

until i=j

b:=x

i:=i+1j:=j-1

if s<j then quicksort(b,s,j)

if i<t then quicksort(b,i,t)

end

begin

write('input data:')

for i:=1 to n do read(a)

writeln

quicksort(a,1,n)

write('output data:')

for i:=1 to n do write(a:6)

writeln

end.

递归是函数体中调用自己,如果不加控制,将无休止的调用自己,直到堆栈溢出。循环是反复执行某一段区域内的代码,如果不加控制,就会形成死循环。所以不管是递归还是循环,都要设定一定的条件,以结束递归或循环。实际问题中,有一些问题是递归的,这样的问题使用递归程序解决感觉会自然些,程序也会简单些,但是,递归要经常调用函数,开销(内存、时间)大,有些问题就不适宜使用,循环不需要调用自身,甚至可以不调用函数,效率高,不过,要将递归问题改成非递归,可能就要动动脑筋。上例中pow2 函数实现部分指数计算功能,(b, n-1) =3 这个提法有问题,因为递归调用时,在返回之前系统堆栈上有一大堆(从第一次调用知道条件满足时的次数)的该递归函数,条件满足后这一系列的函数依次返回。上述函数运行过程是这样的: 执行主函数的 pow2(3, 2)后:1: b = 3 n = 2 此时 n >0pow2 调用自身(即递归调用): pow2(b, n-1) * b 后:2: b = 3 n = 1 此时 n >0pow2 调用自身(即递归调用): pow2(b, n-1) * b 后:3: b = 3 n = 0 此时 n = 0, if (n <= 0) 条件满足 1 递归函数第一次(函数最后依次递归调用)返回,值为 14: 上一次 pow2(b, n-1) 返回值为 1,return pow2(b, n-1) * b所以本次(第2次)返回 35: 上一次 pow2(b, n-1) 返回值为 3,return pow2(b, n-1) * b所以本次(第1次)返回 96: 函数main得到 pow2 的返回值 9

循环与递归的本质区别在于内存的使用上,递归是方法调用方法本身,而随着递归的次数的增加,内存的消耗也是不断增长,而在我们写代码时,内存是一个很重要的部分,我们尽量都是减少内存的消耗,以免造成对系统资源的浪费,循环占用的内存很少,每次循环都会释放之前分配的内存,但是很多递归的功能是不能用循环实现的,这就要考虑你要实现的功能了,如果非递归不可完成的功能,我们也不会刻意更改。