算法递归
Posted lilip
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法递归相关的知识,希望对你有一定的参考价值。
递归
实例:在盒子中寻找钥匙
方法1:使用while循环
算法
(1) 创建一个要查找的盒子堆。
(2) 从盒子堆取出一个盒子,在里面找。
(3) 如果找到的是盒子,就将其加入盒子堆中,以便以后再查找。
(4) 如果找到钥匙,则大功告成!
(5) 回到第二步。
代码
def look_for_key(main_box): pile=main_box.make_a_pile_to_look_through() while pile is not empty: box=pile.grap_a_box for item in box: if item.is_a_box(): pile.append(item) elif item.is_a_key(): print(‘found a key‘)
方法2:使用递归
算法
(1) 检查盒子中的每样东西。
(2) 如果是盒子,就回到第一步。
(3) 如果是钥匙,就大功告成!
代码
def look_for_key(box): for item in box: if item.is_a_box(): look_for_key(item) #递归 elif item.is_a_key(): print(‘found a key‘)
如果使用循环,程序的性能可能更高;如果使用递归,程序可能更容易理解。如何选择要看什么对你来说更重要。
基线条件和递归条件
编写递归函数时,必须告诉它何时停止递归。否则会导致无限循环。
递归函数两部分
基线条件(base case)和递归条件(recursive case)
递归条件:指的是函数调用自己
基线条件:指的是函数不再调用自己,从而避免形成无限循环。
示例
def countdown(i): print(i) if i<=0: #基线条件 return else: #递归条件 countdown(i-1) print(countdown(4))
栈
定义
栈(stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。
特点
LIFO,即后进先出(Last in, first out)
调用栈(call stack)
计算机在内部使用被称为调用栈的栈。
示例
def greet2(name): print("how are you," + name + "?") def bye(): print(‘ok bye!‘) def greet(name): print(‘hello,‘+name+‘!‘) greet2(name) print(‘getting ready to say bye..‘) bye() print(greet(‘lilip‘))
调用过程
- 调用greet(‘lilip’),首先为该函数调用分配一块内存
- 打印,hello,lilip!
- 调用greet2(‘lilip’),接着为这个函数调用分配一块内存
- 计算机使用一个栈表示这些内存块,其中第二个内存块位于第一个内存块的上面。
- 打印,how are you,lilip?greet2函数运行完毕,然后从函数调用返回。此时,栈顶的内存块被弹出。
- 栈顶内存块是函数greet,返回到函数greet。
- 打印getting ready to say bye..
- 调用bye()函数,栈顶添加函数bye的内存块
- 打印,ok bye!并从这个函数返回。
- 返回到函数greet,此时运行完毕。从函数greet返回,
调用另一个函数时,当前函数暂停并处于未完成状态。该函数的所有变量的值都还在内存中
这个栈用于存储多个函数的变量,被称为调用栈。
递归调用栈
递归函数也使用调用栈!
示例
阶乘递归函数
def fact(x): if x==1: return 1 else: return x*fact(x-1) print(fact(3))
调用过程
代码 |
调用栈 |
备注 |
||||||||||||||||||
fact(3) |
|
第一次调用fact x=3 |
||||||||||||||||||
if x==1: |
|
|
||||||||||||||||||
else: |
|
|
||||||||||||||||||
return x*fact(x-1) |
|
递归调用 |
||||||||||||||||||
if x==1: |
|
现在位于对fact的第二次调用中 x=2 最上面的函数调用是当前所处的调用 |
||||||||||||||||||
else: |
|
两个函数调用都有变量x,但这些x变量的值不同 |
||||||||||||||||||
return x*fact(x-1) |
|
在栈顶层调用中,不能访问下面其他内存块调用的x变量,反之亦然 |
||||||||||||||||||
if x==1: |
|
|
||||||||||||||||||
return 1 |
|
从栈中弹出第一个方块,意味着将从这个调用返回,返回1 |
||||||||||||||||||
return x*fact(x-1) |
|
x为2 fact(x-1)返回1 最终返回2 |
||||||||||||||||||
return x*fact(x-1) |
|
x为3 fact(x-1)返回2 最终返回6 |
注意:
- 每个fact调用都有自己的x变量。在一个函数调用中不能访问另一个的x变量。
- 每个函数调用都要占用一定的内存,如果栈很高,就意味着计算机存储了大量函数调用的信息。
小结
- 递归指的是调用自己的函数。
- 每个递归函数都有两个条件:基线条件和递归条件。
- 栈有两种操作:压入和弹出。
- 所有函数调用都进入调用栈。
- 调用栈可能很长,这将占用大量的内存。
以上是关于算法递归的主要内容,如果未能解决你的问题,请参考以下文章
JavaScript - 代码片段,Snippets,Gist
有人可以解释啥是 SVN 平分算法吗?理论上和通过代码片段[重复]