前言
个人觉得栈这种数据结构算是在大学学的最简单的一种数据结构了,队列都好歹需要两个指针,而栈只需要一个指针,开销更小性能更快。并且在学习的过程和敲代码的时间里还是得到了不少的收益。
简介
栈(Stack)是一种基于先进后出(LIFO)原则的数据结构。栈的操作主要包括入栈(Push)和出栈(Pop)。栈通常用于在算法中实现递归、解决括号匹配问题、追踪函数调用等场景。以下是栈的一些基本特点和操作:
特点:
先进后出(LIFO): 最后入栈的元素将是第一个出栈的元素。
只允许在栈顶进行操作: 只能访问、添加或移除栈顶的元素。
基本操作
Push(入栈): 将元素添加到栈顶。
Pop(出栈): 移除栈顶的元素。
Top(查看栈顶元素): 获取栈顶元素但不移除。
isEmpty(判断栈是否为空): 检查栈是否为空。
Size(获取栈的大小): 获取栈中元素的个数。
实现方式
数组实现: 使用数组可以简单地实现栈,通过指针(栈顶指针)来记录栈顶位置。
链表实现: 使用链表也可以实现栈,每个节点保存元素值和指向下一个节点的指针。
应用场景
函数调用栈: 用于保存函数调用的上下文信息。
表达式求值: 用于解决中缀表达式转后缀表达式的问题。
括号匹配: 检查表达式中的括号是否匹配。
递归算法: 递归函数调用时使用栈保存每一层的状态。
代码及其实现思路
定义节点类
在这里链表和数组都将用这个节点来作为存储数据的节点
class StackNode:
def __init__(self,value,next = None):
self.value = value
self.next = next
链表实现
实现了使用链表实现的栈(StackList
类)。核心思想是通过链表的头指针 __head
来表示栈顶,使用链表节点实现元素的入栈(push
)、出栈(pop
)、查看栈顶元素(peek
)等操作。以下是核心思想的简要描述:
-
初始化: 在构造函数中初始化栈的头指针
__head
为None
,设置栈的容量capacity
和当前栈中元素数量size
。 -
判断是否为空或已满: 提供
isEmpty
和isFull
方法,用于判断栈是否为空或已满。 -
入栈操作(
push
):- 如果栈满了,返回
False
。 - 如果栈为空,将新元素作为头指针。
- 如果栈非空,将新元素插入到头指针前,并更新头指针。
- 如果栈满了,返回
-
出栈操作(
pop
):- 如果栈为空,返回
False
。 - 获取头指针指向的节点,并将头指针指向下一个节点,断开原头指针与新头指针的连接。
- 更新栈中元素数量。
- 如果栈为空,返回
-
查看栈顶元素(
peek
): 返回头指针指向的节点的值。
#链表实现栈
class StackList:
# head来作为头指针,capacity来确定栈的大小,size来作为判断栈里面元素的数量
def __init__(self,capacity):
self.__head = None
self.capacity = capacity
self.size = 0
#判断是否为空
def isEmpty(self):
if self.size == 0:
return True
return False
#判断是否已满
def isFull(self):
if self.size == self.capacity:
return True
return False
#栈顶压入元素
def push(self,node):
if self.isFull():
return False
#走进栈逻辑
if self.isEmpty():
self.__head = node
else:
node.next = self.__head
self.__head = node
self.size += 1
return True
#从栈顶弹出元素
def pop(self):
if self.isEmpty():
return False
prever = self.__head
self.__head = self.__head.next
prever.next = None
self.size -=1
return prever
#从栈顶返回元素,但不弹出
def peek(self):
current = self.__head
return current
数组实现
这段代码实现了使用数组实现的栈(StackNums
类)。以下是代码的核心思想的简要描述:
-
初始化: 在构造函数中,通过
np.zeros
创建了一个容量为capacity
的对象数组__array
,并初始化了头指针__head
和栈的大小size
。 -
判断是否为空或已满: 提供了
isEmpty
和isFull
方法,用于判断栈是否为空或已满。 -
入栈操作(
push
):- 如果栈满了,返回
False
。 - 将新元素压入栈顶,更新头指针和栈的大小。
- 如果栈满了,返回
-
出栈操作(
pop
):- 如果栈为空,返回
False
。 - 弹出栈顶元素,将栈顶元素置为
None
,更新头指针和栈的大小。
- 如果栈为空,返回
-
查看栈顶元素(
peek
):- 如果栈为空,返回
False
。 - 返回栈顶元素的值。
- 如果栈为空,返回
这段代码通过数组实现栈的基本操作,使用了头指针 __head
来动态维护栈顶的位置。注意,这里使用了 NumPy 数组,并将数组的数据类型设置为 object
,以允许存放任意类型的对象。入栈和出栈的操作时间复杂度都为 O(1)。
class StackNums:
#head来作为头指针,capacity来确定栈的大小
def __init__(self,capacity):
self.__head = 0
self.capacity = capacity
self.__array = np.zeros(capacity, dtype=object) #创建对象数组
self.size = 0
#判断是否为空
def isEmpty(self):
if self.size == 0:
return True
return False
#判断是否已满
def isFull(self):
if self.size == self.capacity:
return True
return False
#栈顶压入元素
def push(self,node):
if self.isFull():
return False
self.__array[self.__head] = node
self.__head += 1
self.size += 1
return True
#栈顶弹出元素
def pop(self):
if self.isEmpty():
return False
result = self.__array[self.__head-1]
self.__array[self.__head - 1] = None
self.__head -= 1
self.size -= 1
return result
#栈顶返回元素但不弹出
def peek(self):
if self.isEmpty():
return False
return self.__array[self.__head - 1]
好了,以上就是两种栈的实现方式。