递归
1. 递归
循环和递归可以实现相同的功能,如:
- 循环
def look_for_key(main_box)
pile = main_box.make_a_pile_to_look_thorugh()
while pile is not empty:
box = pile.grab_a_box()
for item in box:
if item.is_a_box():
pile.append(item)
elif item.is_a_key():
print "find the key!"
- 递归
def look_for_key(box)
for item in box:
if item.is_a_box():
look_for_key(item)
elif item.is_a_key():
print "find the key!"
如果使用循环,程序的性能可能更高;如果使用递归,程序可能更容易理解。
递归(Recursion)是一种描述和解决问题的基本方法,常用来解决可归纳描述的问题,或者说可分解为结构自相似的问题。所谓结构自相似,是指构成问题的部分与问题本身在结构上相似。这类问题具有的特点是:整个问题的解决可以分为两部分,第一部分是一些特殊或基本的情况,可直接解决,即始基;第二部分与原问题相似,可用类似的方法解决,但比原问题的规模小。
由于第二部分比整个问题的规模小,所以每次递归时第二部分的规模都在缩小,如果最终缩小为第一部分的情况则结束递归。因此,通过递归不断地分解问题,将子问题的解进行综合,完成原问题的求解。
1.1 基线条件和递归条件
编写递归函数时,必须告诉它何时停止递归。因此,每个递归函数都有两个部分:基线条件和递归条件。递归条件指的时函数调用自身,而基线条件指的是函数不调用自己,从而避免形成无限循环。
def countdown(i)
print i
if i < 1: //基线条件
return
else //递归条件
countdown(i)
2. 栈
栈是一种简单的数据结构。
数据存储和读取特点是:“先进后出”。
具备两种操作:压入(插入)和弹出(删除并读取)。
2.1 调用栈
调用栈:栈用于存储多个函数的变量。 计算机在内部使用被称为调用栈的栈。
计算机使用一个栈来表示函数的内存块(调用函数时,函数调用涉及的所有变量的指存储在内存中)。当在一个函数中调用多个另外的函数时:调用另一个函数时,当前函数暂定并处于未完成状态。那么这个栈就还存在。
只有先执行完调用函数,再回到当前函数进行执行。
2.2 递归调用栈
def fact(x)
if x == 1: //基线条件
return 1
else //递归条件
return fact(x-1)*x
每个fact(x)调用都有自己的x变量。在一个函数调用中不能访问另一个的x变量。
使用栈虽然很方便,但是也是需要付出代价:存储详尽的信息可能占用大量的内存。每个函数调用都要占用一定的内存,如果栈很高,就意味着计算机存储了大量函数调用的信息。此时可以选择:重新编写代码,转而使用循环;使用尾递归。
3. 递归应用
3.1 分而治之(D&C)
该方法是一种递归式问题解决方法。
- 问题:农场主分地问题,将一块土地均匀分成方块,且分出的方块要尽可能大。
- 使用D&C解决问题的过程包括两个步骤:(并非可用于解决问题的算法,而是解决问题的思路)
- 找出基线条件,这种条件必须尽可能简单。
- 不断将问题分解(或者说缩小规模),直到符合基线条件。
问题解决:采用递归的思路进行数组求和。
def sum(arr)
if sum[] = 0: //基线条件
return 0
else //递归条件
return sum(x:xs) = x + sum(xs)
Note:函数式编程中没有循环,则用递归来解决。
3.2 快速排序
快速排序是一种常用的排序算法,比选择排序快得多。例如,C语言标准库中的函数qsort实现的就是快速排序。快速排序也使用了D&C。
思路:
- 数组中1个元素和没有元素,则不用排序;
- 数组中2个元素,则直接排序;
- 数组中3个元素,确定基准后。则编程2/0个元素或者1/1个元素的排序;
- 依次进行归纳推理。
def quicksort(array):
if len(array) < 2:
return array
else:
pivot = array[0]
less = [i for i in array[1:] if i <= pivot]
greater = [i for i in array[1:] if i > pivot]
return quicksort(less) + [pivot] + quicksort(greater)
算法运行的最佳情况和最糟糕情况:
-
快速排序中,层数为O(log n)(用技术术语说,调用栈的高度为O(log n)),而每层需要的时间为O(n)。因此整个算法需要的时间为O(n) * O(log n) = O(n log n)。这就是最佳情况。
-
在最糟情况下,有O(n)层,因此该算法的运行时间为O(n) * O(n) = O(n2)。
最佳情况也是平均情况。只要你每次都随机地选择一个数组元素作为基准值,快速排序的平均运行时间就将为O(n log n)。快速排序是最快的排序算法之一,也是D&C典范。
3.3 阶乘
long fact(int n)
{
if(n==1)
return 1;
else
return n*fact(n-1);
}
3.4 在整型数组中找最大元素
int maxint(int A[], int k1, int k2)
{
if(k1==k2)
return A[k1];
else{
m=maxint(A[], k1+1, k2);
return(A[k1]>m)?A[k1]:m;
}
}
3.5 计算二叉树高度
int getHeight(BiTree root)
{
if(!root) return 0;
esle
{
LH=getHeight(root->lchild);
RH=getHeight(root->rchild);
if(LH>RH) return LH+1;
else return RH+1;
}
}

被折叠的 条评论
为什么被折叠?



