算法入门——递归与栈

目录

递归

 栈的操作

调用栈

 python中实现一个栈

总结


 

递归

什么是递归?递归就是方法自己调用自己。比如下面这个例子

def fun(n):    print(n)    fun(n-1)if __name__ == '__main__':    fun(10)

它就是个递归函数,但是你会发现它会一直运行下去

109876.....

但这样就会导致很多错误,我想没人会要一个无线循环的函数吧,所以我们需要有跳出循环的条件,正因为如此,每个递归函数有两部分:基线条件(让函数知道何时停止调用)和递归条件(函数调用自己),比如我们给上面的函数添加基线条件

def fun(n):    print(n)    if n<8:        return    else:        fun(n-1)if __name__ == '__main__':    fun(10)

运行结果:

10987

这样这个函数就变得合理了。

但在调用递归函数的时候得注意递归的深度,用python编写递归函数,它的默认最大递归深度为1000,如果递归数超过这个量了,出来的值就可能不对,比如这个题

def funb(n):    if n>=1:        return 1/n*funb(n-1)    else:        return 1def func(k):    e=0    for i in range(1,k+1):        e+=funb(i)    return eif __name__ == '__main__':    k=int(input('>5的正整数k
'))    x=func(k)    print('%.10f'%x)

栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

简单来说,栈就是一种只能在表尾进行插入和删除操作的线性表。

它按照后进先出的原则存储数据。

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Lit5oSP54Gs,size_20,color_FFFFFF,t_70,g_se,x_16

 栈的操作

压入(插入)和弹出(删除并读取)

调用栈

计算机内部使用的栈称为调用栈。

调用栈最经常被用于存放子程序的返回地址。在调用任何子程序时,主程序都必须暂存子程序运行完毕后应该返回到的地址。因此,如果被调用的子程序还要调用其他的子程序,其自身的返回地址就必须存入调用栈,在其自身运行完毕后再行取回。在递归程序中,每一层次递归都必须在调用栈上增加一条地址,因此如果程序出现无限递归(或仅仅是过多的递归层次),调用栈就会产生栈溢出

调用栈的主要功能是存放返回地址。除此之外,调用栈还用于存放:

  • 本地变量:子程序的变量可以存入调用栈,这样可以达到不同子程序间变量分离开的作用。

  • 参数传递:如果寄存器不足以容纳子程序的参数,可以在调用栈上存入参数。

  • 环境传递:有些语言(如PascalAda)支持“多层子程序”,即子程序中可以利用主程序的本地变量。这些变量可以通过调用栈传入子程序。

如下面这个函数

def fun1(name):    print('hello',name)    fun2(name)    print('hi',name)    fun3()def fun2(name):    print('==',name,'==')def fun3():    print('hello python')if __name__ == '__main__':    fun1('tutu')

运行结果:

hello tutu== tutu ==hi tutuhello python

它的栈的调用过程大概为这样

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Lit5oSP54Gs,size_20,color_FFFFFF,t_70,g_se,x_16

 当我们调用fun2的时候你会发现fun1只执行了一部分,即当我们调用另外一个函数时,当前函数暂停并处于未完成状态,就是当前函数挂起了,此时该函数的所有变量都在内存中。

同时递归函数也使用调用栈

如下面这个计算阶乘的函数

def fun(n):    if n==1:        return 1    else:        return n*fun(n-1)if __name__ == '__main__':    print(fun(3))

运行结果:

6

watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5Lit5oSP54Gs,size_20,color_FFFFFF,t_70,g_se,x_16

 python中实现一个栈

栈具有的操作:
Stack() 创建一个新的空栈
push(item) 添加一个新的元素item到栈顶
pop() 弹出栈顶元素
peek() 返回栈顶元素
is_empty() 判断栈是否为空
size() 返回栈的元素个数

class Stack():    """"创建一个栈"""    def __init__(self):        self.items=[]    """判断是否为空"""    def is_empty(self):        return self.items==[]    """添加一个新的元素到栈顶"""    def push(self,item):        self.items.append(item)    """弹出栈顶元素"""    def pop(self):        self.items.pop()    """返回栈顶元素"""    def peek(self):        return self.items[len(self.items)-1]    """返回栈的元素个数"""    def size(self):        return len(self.items)if __name__ == '__main__':    s=Stack()    # 判读栈是否为空    print(s.is_empty())    # 压入三个元素    s.push(1)    s.push(2)    s.push(3)    print(s.items)    # 弹出    s.pop()    print(s.items)    # 返回栈顶元素    print(s.peek())    # 返回栈的元素个数    print(s.size())

运行结果:

True[1, 2, 3][1, 2]22

虽然使用栈很方便,但是也有缺点,每个函数的调用有需要占用一定的内存,如果栈很高,就意味着计算机存储了大量的函数调用信息,会耗费大量的内存,这时候大家可以考虑使用循环。

总结

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

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值