算法简介:递归实现与应用

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解决问题的过程包括两个步骤:(并非可用于解决问题的算法,而是解决问题的思路
    1. 找出基线条件,这种条件必须尽可能简单。
    2. 不断将问题分解(或者说缩小规模),直到符合基线条件。

问题解决:采用递归的思路进行数组求和。

def sum(arr)
	if sum[] = 0:  //基线条件
		return 0
	else      //递归条件
		return sum(x:xs) = x + sum(xs)

Note:函数式编程中没有循环,则用递归来解决。

3.2 快速排序

快速排序是一种常用的排序算法,比选择排序快得多。例如,C语言标准库中的函数qsort实现的就是快速排序。快速排序也使用了D&C。
思路:

  1. 数组中1个元素和没有元素,则不用排序;
  2. 数组中2个元素,则直接排序;
  3. 数组中3个元素,确定基准后。则编程2/0个元素或者1/1个元素的排序;
  4. 依次进行归纳推理。
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;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值