栈
栈的定义
-
官方定义:
- 栈(Stack)是一个后进先出(Last in first out,LIFO)的线性表,它要求只在表尾进行删除和插入操作。可以这样讲,栈是前面讲过的线性表的一种具体形式。
-
小甲鱼定义:
- 所谓的栈,其实也就是一个特殊的线性表(顺序表、链表),但是它在操作上有一些特殊的要求和限制
- 栈的元素必须“后进先出”。
- 栈的操作只能在这个线性表的表尾进行。
注:对于栈来说,这个表尾称为栈的栈顶(top),相应的表头称为栈底(bottom)
-
稍微介绍一下关键名词:
- 线性表:栈也是一种线性表,前面详细介绍过线性表,它表达的是一种数据的逻辑关系。也就是在栈内各个元素是相邻的。当然在具体实现上也分
数组和链表实现
,他们的物理存储结构不同。但是逻辑结构(实现的目的
)相同。 - 栈顶栈底: 这个描述是偏向于逻辑上的内容,因为大家知道
数组在末尾插入删除
更容易,而单链表通常在头插入删除
更容易。所以数组可以用末尾做栈顶,而链表可以头做栈顶。
- 线性表:栈也是一种线性表,前面详细介绍过线性表,它表达的是一种数据的逻辑关系。也就是在栈内各个元素是相邻的。当然在具体实现上也分
使用场景
栈这种后进先出的数据结构应用是非常广泛的:
- 符号匹配
- 计算机表达式的转换
- CPU内部栈主要是用来进行子程序调用和返回
- 进制转换
- 浏览器的后退
栈的顺序存储结构
栈的本质是一个线性表,线性表有两种存储形式,那么栈也有分为栈的顺序存储结构和栈的链式存储结构。
最开始栈中不含有任何数据,叫做空栈,此时栈顶就是栈底。然后数据从栈顶进入,栈顶栈底分离,整个栈的当前容量变大。数据出栈时从栈顶弹出,栈顶下移,整个栈的当前容量变小。
栈的顺序结构操作
栈可以用顺序表方式实现,也可以用链表的方式实现,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