美文网首页我爱编程
代码小工蚁的#《算法图解》#学习笔记-C3递归

代码小工蚁的#《算法图解》#学习笔记-C3递归

作者: 代码小工蚁 | 来源:发表于2018-05-27 16:59 被阅读27次

代码小工蚁的#《算法图解》#学习笔记-C3递归
C3 递归recursion

一、调用栈

执行栈(execution stack),又称控制栈(control stack)、运行时栈(run-time stack)和调用栈(call stack)。
栈(stack)是限定仅在表尾进行压入(插入)和弹出(删除并读取)操作的线性表。
表尾端称为栈顶(top),相应地,表头端称为栈底(bottom)。[1]
栈遵循LIFO后进先出(Last In First Out)原则。

压入(插入)push (insert)
弹出(删除并读取)pop (remove and read)

调用栈保持程序调用的返回地址,以及本地变量、参数传递、环境传递等数据。
无限递归(Infinite recursion)或过多的堆栈层级(占用大量的内存)会导致堆栈溢出(stack overflow)

一般而言,高级语言会将调用栈的细节隐藏至后台。

扩展:
世界上最大的开发者社区StackOverflow:
https://stackoverflow.com/

二、递归

从一个故事开始的递归:

从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?
从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?
从前有座山,山里有座庙,庙里有个老和尚,正在给小和尚讲故事呢!故事是什么呢?
……

从前有座山,山里有座庙...图片来源知乎[2]

在计算机中,递归是指一种通过重复将问题分解为同类的子问题的方法。
换一种表述就是函数自己调用自己。
每个递归函数都有两个条件:基线条件base case和递归条件recursive case。
基线条件:函数不再调用自己,避免无限循环。
递归条件:函数调用自己。

好处:递归使函数的定义和算法的描述比使用非递归方法更简明。

递归的强大之处在于它允许用户用有限的语句描述无限的对象。
因此,在计算机科学中,递归可以被用来描述无限步的运算,尽管描述运算的程序是有限的。
——Nicklaus Wirth(对,就是提出“算法+数据结构=程序”的尼古拉斯·沃斯)[3]

缺点:递归调用可能占用大量的内存。
处理:重写代码改用循环;使用尾递归tail recursion。

递归应用:求阶乘5!
5!= 5 * 4 * 3 * 2 * 1

代码片断:

def fact(x):
    if x == 1:
        return 1
    else:
        return x*fact(x-1)

print('5! = ', fact(5))

注意代码中的基线条件与递归条件。
python中已有 math.factorial() 方法可直接求阶乘。

扩展:递归典型问题:梵塔问题(汉诺塔问题)

相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。
该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘。
游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。
操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。[4]

网络图片-汉诺塔玩具(侵删)

C语言源码参考[5]

代码片断:

# coding=utf-8

# 汉诺塔问题演示

def hanoi(n, p1, p2, p3):
    # 移动步数steps,全局变量
    global steps
    steps += 1
    if n == 1:
        print('Move sheet {} from {} to {}.'.format(n, p1, p3))
        print('-' * 30)
    else:
        hanoi(n-1, p1, p3, p2)
        print('Move sheet {} from {} to {}'.format(n, p1, p3))
        hanoi(n-1, p2, p1, p3)
    return steps


if __name__ == '__main__':
    n = int(input('请输入盘数1-8:'))
    # 移动步数统计steps
    steps = 0
    steps_num = hanoi(n,'A', 'B', 'C')
    print(steps_num)
4盘汉诺塔移动演示

按要求将64个盘从A柱移动到C柱,按1秒移一下,完成任务需要5800多亿年!!!

(2**64 - 1)/3600/24/365

小伙伴们输入数字时就不要输入64了,不信你试试。


[1]百度百科:执行栈
https://baike.baidu.com/item/%E6%89%A7%E8%A1%8C%E6%A0%88/22105693?fr=aladdin

[2]图片来自:知乎@ninechapter 若侵删
https://www.zhihu.com/question/20507130

[3]维基百科
https://zh.wikipedia.org/wiki/%E9%80%92%E5%BD%92_(%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6)

[4]百度百科:汉诺塔问题
https://baike.baidu.com/item/%E6%B1%89%E8%AF%BA%E5%A1%94%E9%97%AE%E9%A2%98/1945186?fr=aladdin

[5]汉诺塔Tower of Hanoi
http://www.it165.net/pro/html/201508/51045.html

相关文章

网友评论

    本文标题:代码小工蚁的#《算法图解》#学习笔记-C3递归

    本文链接:https://www.haomeiwen.com/subject/uvobjftx.html