数据结构与算法之栈

在这里插入图片描述

栈的定义

  • 官方定义:

    • 栈(Stack)是一个后进先出(Last in first out,LIFO)的线性表,它要求只在表尾进行删除和插入操作。可以这样讲,栈是前面讲过的线性表的一种具体形式。
  • 小甲鱼定义:

    • 所谓的栈,其实也就是一个特殊的线性表(顺序表、链表),但是它在操作上有一些特殊的要求和限制
    • 栈的元素必须“后进先出”。
    • 栈的操作只能在这个线性表的表尾进行。

    注:对于栈来说,这个表尾称为栈的栈顶(top),相应的表头称为栈底(bottom)

  • 稍微介绍一下关键名词:

    • 线性表:栈也是一种线性表,前面详细介绍过线性表,它表达的是一种数据的逻辑关系。也就是在栈内各个元素是相邻的。当然在具体实现上也分数组和链表实现,他们的物理存储结构不同。但是逻辑结构(实现的目的)相同。
    • 栈顶栈底: 这个描述是偏向于逻辑上的内容,因为大家知道数组在末尾插入删除更容易,而单链表通常在头插入删除更容易。所以数组可以用末尾做栈顶,而链表可以头做栈顶。

使用场景

栈这种后进先出的数据结构应用是非常广泛的:

  1. 符号匹配
  2. 计算机表达式的转换
  3. CPU内部栈主要是用来进行子程序调用和返回
  4. 进制转换
  5. 浏览器的后退

栈的顺序存储结构

栈的本质是一个线性表,线性表有两种存储形式,那么栈也有分为栈的顺序存储结构和栈的链式存储结构。

最开始栈中不含有任何数据,叫做空栈,此时栈顶就是栈底。然后数据从栈顶进入,栈顶栈底分离,整个栈的当前容量变大。数据出栈时从栈顶弹出,栈顶下移,整个栈的当前容量变小。

在这里插入图片描述

栈的顺序结构操作

栈可以用顺序表方式实现,也可以用链表的方式实现,Python本身已有顺序表(List、Tupple)的实现。因此这里可以用list直接实现栈。

执行过程

在这里插入图片描述

创建一个空栈
  • 代码实现

    class Stack(object):
        """栈"""
        def __init__(self):
             self.items = []
             
    
判断是否为空
  • 代码实现

        def is_empty(self):
            """
            判断是否为空
            :return:
            """
            return self.items == []
            
    
进栈

栈的插入操作(Push),叫做进栈,也称为压栈,入栈。类似子弹放入弹夹的动作。

  • 代码实现

        def push(self, item):
            """
            进栈
            :param item:
            :return:
            """
            self.items.append(item)
            
    
出栈

栈的删除操作(Pop),叫做出栈,也称为弹栈。如同弹夹中的子弹出夹。

  • 代码实现

        def pop(self):
            """
            出栈
            :return:
            """
            return self.items.pop()
            
    
栈顶元素
  • 代码实现

        def peek(self):
            """
            返回栈顶元素
            :return:
            """
            return self.items[len(self.items)-1]
            
    
栈的大小
  • 代码实现
    def size(self):
        """
        返回栈的大小
        :return:
        """
        return len(self.items)
        
测试
  • 代码实现

    if __name__ == "__main__":
        # 初始化一个栈
        stack = Stack()
    
        # 将hello,world,itcast压入栈
        stack.push("hello")
        stack.push("world")
        stack.push("itcast")
    
        # 查看栈的大小
        print(stack.size())
    
        # 打印栈顶元素
        print(stack.peek())
    
        # 弹出栈
        print(stack.pop())
        print(stack.pop())
        print(stack.pop())
    
        # 查看栈的大小
        print(stack.size())
    
        # 查看是否为空栈
        print(stack.is_empty())
        
    
十进制转换为二进制数
题目

利用栈的数据结构特点,将十进制转换为二进制数。

代码实现
def dec2bin(num):
    """
    十进制转换为二进制
    :param num: 要转换的数字
    :return:
    """
    if num < 1 :
        print("该数字小于1,转换功能未实现")
    else:
        stack = Stack()
        while(num > 0):
            mod = num % 2 # 除2取余
            stack.push(mod) # 将余数压入栈
            num = num // 2 # 取整除 - 返回商的整数部分(向下取整)
            # print(num)
        v = stack.pop() # 最后的一个余数为0  将其弹出

        while (stack.is_empty() == False):
            v = v * 10 + stack.pop()
        return v
print(dec2bin(1))

逆波兰表达式
逆波兰表达式概念

对于(1-2)*(4+5),如果用逆波兰表示法,应该是这样:1 2 – 4 5 + *

  • 数字1和2进栈,遇到减号运算符则弹出两个元素进行运算并把结果入栈。

在这里插入图片描述

  • 4和5入栈,遇到加号运算符,4和5弹出栈,相加后将结果9入栈。

在这里插入图片描述

  • 然后又遇到乘法运算符,将9和-1弹出栈进行乘法计算,此时栈空并无数据压栈,-9为最终运算结果!

在这里插入图片描述

代码实现(leetcode 150)
class Solution(object):
    def evalRPN(self, tokens):
        """
        :type tokens: List[str]
        :rtype: int
        """
        stack = []
        for item in tokens:
            if item in ["+", "-", "*", "/"]:
                if item == "+":
                    temp = int(stack[-2]) + int(stack[-1])
                elif item == "-":
                    temp = int(stack[-2]) - int(stack[-1])
                    # print temp                
                elif item == "*":
                    temp = int(stack[-2]) * int(stack[-1])             
                elif item == "/":
                    temp = int(float(stack[-2])/ float(stack[-1]))                    
                stack.pop()
                stack.pop()
                stack.append(temp)
                
            else:
                stack.append(item)                
        return int(stack[0])
        

栈的链式存储结构

栈的链式存储结构,简称栈链。(通常我们用的都是栈的顺序存储结构存储,链式存储我们作为一个知识点,大家知道就好!)

栈因为只是栈顶来做插入和删除操作,所以比较好的方法就是将栈顶放在单链表的头部,栈顶指针和单链表的头指针合二为一。

在这里插入图片描述

栈的链式结构操作

创建一个节点
  • 代码实现

    class Node(object):
    
        """
        链表的节点
        """
        def __init__(self, data=None):
            self.data = data
            self.next = None
    
    
    class LKStack(object):
        """
        栈
        """
    
        def __init__(self,node = None):
            self.top = node
            self.count = 0	
            
    
判断是否为空
  • 代码实现

        def is_empty(self):
            """
            判断栈是否为空
            :return:True/False
            """
            return self.top is None
            
    
栈顶元素
  • 代码实现

        def get_top(self):
            """
            返回栈顶元素
            :return:
            """
            return self.top.data
            
    
栈的大小
  • 代码实现

        def get_length(self):
            """
            栈的大小
            :return:
            """  
            return self.count
            
    
进栈
  • 代码实现

        def push(self, elem):
            """
            压栈
            :param elem:
            :return:
            """
            node = Node(elem)
            if self.is_empty():
                self.top = node
            else:
                node.next = self.top
                self.top = node
            self.count += 1
    
    
    
出栈
  • 代码实现

        def pop(self):
            """
            出栈
            :return:
            """
            if self.is_empty():
                raise IndexError("Stack is empty!")
            else:
                self.count -= 1
                elem = self.top.data
                self.top = self.top.next  
                return elem
    
    
测试
  • 代码实现

    if __name__ == '__main__':
    
        # 实例化栈
        lks = LKStack()
    
        # 判断栈是否为空
        print(lks.is_empty())
        print("---" * 20)
    
        # 栈的长度
        print(lks.get_length())
        print("---" * 20)
    
        # 进栈
        for i in range(1, 5):
            lks.push(i)
    
        # 从栈顶开始显示各节点值
        lks.show_stack()
        print("---"*20)
    
        # 出栈
        c = lks.pop()
        print(c)
        print("---" * 20)
    
        lks.show_stack()
        print("---" * 20)
    
        print(lks.is_empty())
        print("---" * 20)
    

参考资料

小甲鱼数据结构与算法:https://www.bilibili.com/video/av2975983?from=search&seid=9609762438302042957

https://github.com/jamesyangget/python-data-structure-and-algorithm

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值