算法递归

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‘))

  

调用过程

  1. 调用greet(‘lilip’),首先为该函数调用分配一块内存
  2. 打印,hello,lilip!
  3. 调用greet2(‘lilip’),接着为这个函数调用分配一块内存
  4. 计算机使用一个栈表示这些内存块,其中第二个内存块位于第一个内存块的上面。
  5. 打印,how are you,lilip?greet2函数运行完毕,然后从函数调用返回。此时,栈顶的内存块被弹出。
  6. 栈顶内存块是函数greet,返回到函数greet。
  7. 打印getting ready to say bye..
  8. 调用bye()函数,栈顶添加函数bye的内存块
  9. 打印,ok bye!并从这个函数返回。
  10.  返回到函数greet,此时运行完毕。从函数greet返回,

 

调用另一个函数时,当前函数暂停并处于未完成状态。该函数的所有变量的值都还在内存中

这个栈用于存储多个函数的变量,被称为调用栈。

 

递归调用栈

递归函数也使用调用栈!

示例

阶乘递归函数

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

  

调用过程

代码

调用栈

备注

fact(3)

fact

x

3

 

第一次调用fact

x=3

if x==1:

fact

x

3

 

 

else:

fact

x

3

 

 

return x*fact(x-1)

fact

x

2

fact

x

3

 

递归调用

if x==1:

fact

x

2

fact

x

3

 

现在位于对fact的第二次调用中

x=2

最上面的函数调用是当前所处的调用

else:

fact

x

2

fact

x

3

 

两个函数调用都有变量x,但这些x变量的值不同

return x*fact(x-1)

fact

x

1

fact

x

2

fact

x

3

 

在栈顶层调用中,不能访问下面其他内存块调用的x变量,反之亦然

if x==1:

fact

x

1

fact

x

2

fact

x

3

 

 

return 1

fact

x

1

fact

x

2

fact

x

3

 

从栈中弹出第一个方块,意味着将从这个调用返回,返回1

return x*fact(x-1)

fact

x

2

fact

x

3

 

x为2

fact(x-1)返回1

最终返回2

return x*fact(x-1)

fact

x

3

 

x为3

fact(x-1)返回2

最终返回6

 

注意:

  1. 每个fact调用都有自己的x变量。在一个函数调用中不能访问另一个的x变量。
  2. 每个函数调用都要占用一定的内存,如果栈很高,就意味着计算机存储了大量函数调用的信息。

 

小结

  • 递归指的是调用自己的函数。
  • 每个递归函数都有两个条件:基线条件和递归条件。
  • 栈有两种操作:压入和弹出。
  • 所有函数调用都进入调用栈。
  • 调用栈可能很长,这将占用大量的内存。

 

以上是关于算法递归的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript - 代码片段,Snippets,Gist

以下代码片段的算法复杂度

有人可以解释啥是 SVN 平分算法吗?理论上和通过代码片段[重复]

片段(Java) | 机试题+算法思路+考点+代码解析 2023

CSP核心代码片段记录

算法漫游指北(第十篇):泛型递归递归代码模板递归思维要点分治算法回溯算法