递归是一种解决问题的方法,将问题分解为更小的子问题,直到得到一个足够小的问题可以被很简单的解决。通常递归涉及函数调用自身。递归允许我们编写优雅的解决方案,解决可能很难编程的问题。

1 递归算法的三定律

在介绍递归思想的简单例子前,我们先了解下递归算法的三个重要的定律:
1.1 递归算法必须具有基本情况。
1.2 递归算法必须改变其状态并向基本情况靠近。
1.3 递归算法必须以递归方式调用自身。

2 计算整数列表和

假设没有 while 循环或 for 循环。你将如何计算整数列表的总和?可以使用以下的简化序列来计算最终的和。
这里写图片描述
把这一系列的调用想象成一系列的简化。 每次我们进行递归调用时,我们都会解决一个较小的问题,直到达到问题不能减小的程度。下图展示了对列表[1,3,5,7,9] 求和所需的一系列递归调用。
这里写图片描述

python实现代码如下:

def listsum(numList):
   if len(numList) == 1:
        return numList[0]
   else:
        return numList[0] + listsum(numList[1:])

print(listsum([1,3,5,7,9]))

3 整数转换为任意进制字符串

首先思考基本情况是什么?

如果我们将数字 769 分成三个单个位数字,7,6 和 9,那么将其转换为字符串很简单。数字小于 10 听起来像一个好的基本情况。并且用除法的数学运算似乎可以减少一个数字。余数除法为我们提供了一个明确的方向。

知道我们的基本情况是什么意味着整个算法将分成三个部分:
1. 将原始数字减少为一系列单个位数字。
2. 使用查找将单个位数字数字转换为字符串。
3. 将单个位字符串连接在一起以形成最终结果。

操作思路如下所示:
这里写图片描述

python实现代码如下:

def toStr(n,base):
   convertString = "0123456789ABCDEF"
   if n < base:
      return convertString[n]
   else:
      return toStr(n//base,base) + convertString[n%base]

print(toStr(1453,16))

4 栈帧实现递归

在上个例子中,假设不是将递归调用的结果与来自 convertString 的字符串拼接到 toStr,而是利用栈实现结果,该怎么做呢?
我们修改了算法,以便在进行递归调用之前将字符串入栈。此修改的算法的代码如下(关于栈的知识请参见我之前的博文:http://blog.csdn.net/m0_37324740/article/details/78830136):

from pythonds.basic.stack import Stack

rStack = Stack()

def toStr(n,base):
    convertString = "0123456789ABCDEF"
    while n > 0:
        if n < base:
            rStack.push(convertString[n])
        else:
            rStack.push(convertString[n % base])
        n = n // base
    res = ""
    while not rStack.isEmpty():
        res = res + str(rStack.pop())
    return res

print(toStr(1453,16))

栈帧还为函数使用的变量提供了一个作用域。 即使我们重复地调用相同的函数,每次调用都会为函数本地的变量创建一个新的作用域。

参考资料:《problem-solving-with-algorithms-and-data-structure-using-python》
http://www.pythonworks.org/pythonds

posted on 2018-01-23 11:05  未雨愁眸  阅读(446)  评论(0编辑  收藏  举报