理解Python中的堆栈实现

数据结构在编程世界中起着关键作用。它们帮助我们以高效的方式组织数据。堆栈是最简单的数据结构之一。

让我们学习一下堆栈及其在Python中的实现。

什么是堆栈?

堆栈类似于现实生活中的书堆、椅子堆等等。它遵循先进后出(LIFO)原则。这是最简单的数据结构。让我们通过一个现实世界的例子来看一下情况。

假设我们有一堆书如下所示。

当我们想要从顶部取出第三本书时,我们必须先将前两本书从顶部移除。在这里,最顶部的书最后放入书堆,并且最先从书堆取出。数据结构堆栈在编程中遵循相同的先进后出(LIFO)原则。

堆栈的操作

堆栈有两个主要操作

1. push(data)

将数据添加或推入堆栈。

2. pop()

从堆栈中移除或弹出最顶部的元素。

请看下面关于push和pop操作的说明。

我们将编写一些辅助函数,以帮助我们获取有关堆栈的更多信息。

让我们来看看它们。

peek()

返回堆栈的最顶部元素。

is_empty()

返回堆栈是否为空。

足够的关于堆栈数据结构的概念知识。让我们马上进入实现的部分。

我假设你的PC上有python installed,如果没有,你也可以尝试online compiler

堆栈的实现

与其他数据结构的实现相比,堆栈的实现是最简单的。我们可以在Python中以多种方式实现堆栈。

让我们逐个看看它们。

#1. 列表

我们将使用列表在一个类中实现堆栈。让我们看看堆栈的逐步实现。

第1步: 编写一个名为Stack的类。

class Stack:
	pass

第2步: 我们需要在堆栈类中使用一个列表来存储数据。让我们在Stack类中添加一个名为elements的空列表。

class Stack:
	def __init__(self):
		self.elements = []

第3步: 为了将元素推入堆栈,我们需要一个方法。让我们编写一个名为push的方法,该方法接受数据作为参数,并将其追加到elements列表中。

class Stack:
	def __init__(self):
		self.elements = []

	def push(self, data):
		self.elements.append(data)
		return data

第4步: 类似地,让我们编写pop方法,它从堆栈中弹出最顶部的元素。我们可以使用列表数据类型的pop方法。

class Stack:
	## ...
	def pop(self):
		return self.elements.pop()

我们已经完成了具有所需操作的堆栈实现。现在,让我们添加辅助函数以获取有关堆栈的更多信息。

第5步:我们可以使用负索引从堆栈中获取最顶部的元素。代码element[-1]返回列表的最后一个元素。在我们的情况下,它是堆栈的最顶部元素。

class Stack:
	## ...

	def peek(self):
		return self.elements[-1]

第6步:如果elements列表的长度为0,则堆栈为空。让我们编写一个方法,返回元素是否为空。

<class Stack:
## …
def is_empty(self):
return len(self.elements) == 0

我们已经使用列表(list)数据类型完成了栈的实现。

哦!等等,我们刚刚完成了它。但是,我们没有看到如何使用它。那么要如何使用它呢?

来看看如何实现它。我们需要为Stack类创建一个对象才能使用它。这不是什么大问题。让我们首先做这件事。

<class Stack:
## …

if __name__ == '__main__':
stack = Stack()

我们已经创建了栈对象并且准备好使用它。让我们按照以下步骤测试栈的操作。

  • 使用is_empty方法检查栈是否为空。它应该返回True。
  • 使用push方法将数字1、2、3、4、5压入栈中。
  • is_empty方法应该返回False。进行检查。
  • 使用peek方法打印栈顶元素。
  • 使用pop方法从栈中弹出元素。
  • 检查peek元素。它应该返回元素4。
  • 现在,从栈中弹出所有元素。
  • is_empty方法应该返回True。进行检查。

如果通过了上述所有步骤,我们的栈实现就已经完成了。尝试编写上述步骤的代码。

你写代码了吗?不,不要担心,检查下面的代码。

true
print(stack.is_empty())

## 压入元素
stack.push(1)
stack.push(2)
stack.push(3)
stack.push(4)
stack.push(5)

## 再次检查is_empty方法 -> false
print(stack.is_empty())

## 打印栈顶元素 -> 5
print(stack.peek())

## 弹出栈顶元素 -> 5
stack.pop()

## 使用peek方法检查栈顶元素 -> 4
print(stack.peek())

## 弹出所有元素
stack.pop()
stack.pop()
stack.pop()
stack.pop()

## 最后一次检查is_empty方法 -> true
print(stack.is_empty())

太棒了!我们已经使用列表(list)数据类型从头开始完成了栈的实现。如果你运行上面的代码,你将会看到下面提到的输出。

True
False
5
4
True

我们可以直接使用列表(list)数据类型作为栈。上述栈的实现还帮助你理解其他编程语言中的栈实现。

你也可以查看这些与列表相关的文章。

让我们来看看内置模块collections中的deque,它可以作为栈来使用。

#2. collections中的deque

它是作为双向队列实现的。由于它支持从两端添加和删除元素。因此我们可以将其用作栈。我们可以使其遵循栈的LIFO原则。

它是使用其他数据结构实现的,称为双向链表。因此,插入和删除元素的性能是一致的。从链表中间访问元素需要O(n)的时间。由于不需要从堆栈中访问中间元素,因此我们可以将其用作堆栈

在实现堆栈之前,让我们看一下使用队列实现堆栈的方法。

  • append(data) – 用于将数据推入堆栈
  • pop() – 用于从堆栈中移除顶部元素

对于peekis_empty没有替代方法。我们可以打印整个堆栈来代替peek方法。接下来,我们可以使用len方法来检查堆栈是否为空。

让我们使用collections模块中的deque来实现堆栈。

from collections import deque

## 创建deque对象
stack = deque()

## 检查堆栈是否为空-> True
print(len(stack) == 0)

## 推入元素
stack.append(1)
stack.append(2)
stack.append(3)
stack.append(4)
stack.append(5)

## 再次检查堆栈是否为空-> False
print(len(stack) == 0)

## 打印堆栈
print(stack)

## 弹出顶部元素-> 5
stack.pop()

## 打印堆栈
print(stack)

## 弹出所有元素
stack.pop()
stack.pop() 
stack.pop() 
stack.pop() 

## 最后一次检查堆栈是否为空-> True
print(len(stack) == 0)

这就是了。我们已经学习了如何使用内置模块collectionsdeque来实现堆栈。如果您执行上面的程序,您将得到以下输出。

True
False
deque([1, 2, 3, 4, 5])
deque([1, 2, 3, 4])
True

到目前为止,我们已经看到了两种实现堆栈的方法。还有其他方法可以实现堆栈吗?是的!让我们在本教程中看到最后一种实现堆栈的方法。

#3. LifoQueue

名称LifoQueue本身就说明了它遵循LIFO原则。因此我们可以毫不犹豫地将其用作堆栈。它来自内置模块queueLifoQueue提供了一些在堆栈实现中有用的便捷方法。让我们看看它们

  • put(data) – 添加或推入数据到队列
  • get() – 从队列中删除或弹出顶部元素
  • empty() – 返回堆栈是否为空
  • qsize() – 返回队列的长度

让我们使用queue模块中的LifoQueue来实现堆栈。

from queue import LifoQueue

## 创建LifoQueue对象
stack = LifoQueue()

## 检查堆栈是否为空-> True
print(stack.empty())

## 推入元素
stack.put(1)
stack.put(2)
stack.put(3)
stack.put(4)
stack.put(5)

## 再次检查堆栈是否为空-> False
print(stack.empty())

## 弹出所有元素
print(stack.get())
print(stack.get())
print(stack.get())

## 检查堆栈大小
print("Size", stack.qsize())

print(stack.get())
print(stack.get())

## 最后一次检查堆栈是否为空-> True
print(stack.empty())

如果您执行以上程序而不更改它,您将得到下面提到的输出。

True
False
5
4
3
Size 2
2
1
True

堆栈的应用

现在,你已经对栈有足够的了解,可以在编程问题中应用它。让我们看一个问题,并使用栈解决它。

给定一个表达式,编写一个程序来检查括号、大括号和方括号是否正确平衡。

让我们看一些例子。

输入:“[{}]([])”

输出:平衡

输入:“{[}]([])”

输出:不平衡

我们可以使用栈来解决上述问题。让我们看一下解决问题的步骤。

  • 创建一个栈来存储字符。
  • 如果表达式的长度为奇数,则表达式为不平衡
  • 遍历给定的表达式。
    • 如果当前字符是开放括号(或{或[,则将其推入栈中。
    • 否则,如果当前字符是闭合括号)或}或],则从栈中弹出。
    • 如果弹出的字符与起始括号相匹配,则继续,否则括号不平衡。
  • 迭代后,如果栈为空,则方程为平衡,否则方程为不平衡
  • 我们可以使用集合数据类型来检查括号匹配。

    ## 栈
    class Stack: 
        def __init__(self): 
            self.elements = [] 
        
        def push(self, data): 
            self.elements.append(data) 
            return data 
            
        def pop(self): 
            return self.elements.pop() 
        
        def peek(self): 
            return self.elements[-1] 
            
        def is_empty(self): 
            return len(self.elements) == 0
    
    def balance_check(expression):
        ## 检查表达式的长度
        if len(expression) % 2 != 0:
            ## 长度为奇数时不平衡
            return False
        
        ## 用于检查
        opening_brackets = set('([{') 
        pairs = set([ ('(',')'), ('[',']'), ('{','}') ]) 
        
        ## 栈初始化
        stack = Stack()
        
        ## 遍历给定的表达式
        for bracket in expression:
    
            ## 检查当前括号是否打开    
            if bracket in opening_brackets:
                ## 添加到栈中
                stack.push(bracket)
            else:
                ## 弹出栈中的最后一个括号
                popped_bracket = stack.pop()
            
                ## 检查弹出的括号和当前括号是否配对
                if (popped_bracket, bracket) not in pairs:
                    return False
        
        return stack.is_empty()
    
    if __name__ == '__main__':
        if balance_check('[{}]([])'):
            print("平衡")
        else:
            print("不平衡")
        
        if balance_check('{[}]([])'):
            print("平衡")
        else:
            print("不平衡")

    我们可以使用来解决更多问题。上述问题就是其中之一。尽量在你认为最适合的地方应用栈的概念。

    结论

    耶!你已经完成了教程。希望你在制作教程时和我一样享受。教程到此结束。

    编码愉快 🙂 👨‍💻

类似文章