Python中的栈

Python中的栈

在本教程中,我们将学习栈的基础知识,并使用Python代码实现它。

什么是栈

栈是一种线性数据结构,其中的数据按照一层层地排列。它以LIFO(后进先出)的方式存储数据。数据的存储顺序与厨房里的盘子一样,一个盘子放在另一个盘子上面。一个简单的栈的示例是编辑器中的”撤销”功能。撤销功能是基于我们最后完成的事件进行操作的。

我们总是从栈的最后一个盘子开始取。在栈中,新元素被插入到一端,只能从同一端删除元素。

我们可以对栈执行两个操作 – 推入(PUSH)弹出(POP) 。推入操作是添加元素,而弹出操作是从栈中删除元素。

栈的方法

Python提供了一些常用于栈的方法。

  • empty() – 如果栈为空,则返回真。时间复杂度为O(1)。
  • size() – 返回栈的长度。时间复杂度为O(1)。
  • top() – 此方法返回栈的最后一个元素的地址。时间复杂度为O(1)。
  • push(g) – 此方法在栈的末尾添加元素’g’。时间复杂度为O(1)。
  • pop() – 此方法删除栈的顶部元素。时间复杂度为O(1)。

栈的实现

Python提供了多种实现栈的方法。在本节中,我们将讨论使用Python及其模块实现栈的方法。

我们可以用以下方法在Python中实现栈。

  • 列表(List)
  • 双端队列(deque)
  • 优先队列(LifeQueue)

使用列表实现

Python列表可用作栈。它使用 append() 方法将元素插入到列表中,而栈使用 push() 方法。列表还可以使用pop()方法来删除最后一个元素,但列表存在一些缺点。随着列表的增长,列表变得越来越慢。

列表将新元素存储在其他元素的后面。如果列表增长并且超出了一块内存,则Python会分配一些内存。这就是为什么列表变得越来越慢的原因。让我们理解以下示例 –

# initial empty stack
my_stack = []

# append() function to push 
# element in the my_stack 
my_stack.append('x')
my_stack.append('y')
my_stack.append('z')


print(my_stack)

# pop() function to pop 
# element from my_stack in  
# LIFO order 
print('\nElements poped from my_stack:')
print(my_stack.pop())
print(my_stack.pop())
print(my_stack.pop())

print('\nmy_stack after elements are poped:')
print(my_stack) 

输出:

['x', 'y', 'z']

Elements poped from my_stack:
z
y
x  

my_stack after elements are poped:
[]
Traceback (most recent call last):
  File "C:/Users/DEVANSH SHARMA/PycharmProjects/Hello/Stack.py", line 21, in <module>
    print(my_stack.pop())
IndexError: pop from empty list

解释 –

在上面的代码中,我们定义了一个空列表。我们使用 append() 方法逐个插入元素,这与 push() 方法类似。我们还使用 pop() 方法删除元素。 pop() 方法返回列表的最后一个元素。

使用collection.deque实现

collection模块提供了deque类,用于创建Python 堆栈 。deque的发音为”deck”,意思是”double-ended queue”,即双端队列。与列表相比,deque更适合用于执行append和pop操作,因为它的性能更好。时间复杂度为O(1),而列表的时间复杂度为O(n)。

让我们来看下面的示例 –

示例

from collections import deque

my_stack = deque()

# append() function is used to push 
# element in the my_stack 
my_stack.append('a')
my_stack.append('b')
my_stack.append('c')

print('Initial my_stack:')
print(my_stack)

# pop() function is used to pop 
# element from my_stack in  
# LIFO order 
print('\nElements poped from my_stack:')
print(my_stack.pop())
print(my_stack.pop())
print(my_stack.pop())

print('\nmy_stack after elements are poped:')
print(my_stack) 

输出:

Initial my_stack:
deque(['a', 'b', 'c'])
Elements poped from my_stack:
c
b
a
my_stack after elements are poped:
deque([])

说明:

上面的代码几乎与前面的示例相似。唯一的区别是,我们从collection模块导入了deque。

Deque与list的区别

list将元素存储在彼此相邻的位置,并使用连续的内存。这对于诸如索引列表之类的操作非常有效。例如 – 获取 list1[2] 是快速的,因为Python知道特定元素的确切位置。连续的内存还使得切片在列表上运行良好。

list比其他一些对象在 append() 上消耗更多时间。如果连续内存块已满,则会获取另一个块,这可能花费比正常 append() 函数更长的时间。

使用queue模块实现

队列模块具有LIFO队列,与堆栈相同。通常,队列使用 put() 方法添加数据,使用 get() 方法获取数据。

以下是队列中可用的一些方法。

  • empty() – 如果队列为空,则返回true;否则返回false。
  • maxsize() – 此方法用于设置队列中允许的最大元素数量。
  • get() – 它从队列中返回并移除元素。有时队列可能为空,它会等待直到有元素可用。
  • full() – 如果队列已满,则返回True。队列默认定义为maxsize = 0。在这种情况下,它不会返回 True
  • put(item) – 它将元素添加到队列中;如果队列已满,则等待直到有空间可用。
  • put_nowait(item) – 它将元素立即添加到队列中,而不进行延迟。
  • qsize() – 返回队列的大小。

让我们了解一下queue模块的以下示例。

示例

# Implementing stack using the queue module
from queue import LifoQueue 

# Initializing a my_stack stack with maxsize
my_stack = LifoQueue(maxsize = 5)

# qsize() display the number of elements
# in the my_stack 
print(my_stack.qsize()) 

# put() function is used to push
# element in the my_stack 
my_stack.put('x')
my_stack.put('y')
my_stack.put('z')

print("Stack is Full: ", my_stack.full()) 
print("Size of Stack: ", my_stack.qsize()) 

# To pop the element we used get() function
# from my_stack in 
# LIFO order 
print('\nElements poped from the my_stack') 
print(my_stack.get()) 
print(my_stack.get()) 
print(my_stack.get()) 

print("\nStack is Empty: ", my_stack.empty())

输出:

0
Stack is Full:  False
Size of Stack:  3

Elements poped from the my_stack
z
y
x

Stack is Empty:  True

解释 –

在上面的代码中,我们导入了queue模块,这是一个 LIFOqueue 。它的工作方式与堆栈相同,但该模块还包括上面提到的一些附加功能。 我们定义了一个具有maxsize的堆栈,这意味着它可以最多容纳五个值。

初始数组大小为零;我们使用put()方法将三个元素推到堆栈中。现在,我们再次检查堆栈是否为空以及堆栈的大小。我们的堆栈中有三个元素。我们使用get()方法弹出元素。它首先删除最后添加的元素。在删除所有元素后,我们得到一个空堆栈。

Python堆栈和线程

我们还可以在多线程程序中使用Python堆栈。这是一个高级主题,但不常用,因此如果您对线程不感兴趣,可以跳过此部分。

如果我们在程序中使用线程,则列表和deque的行为会有所不同。在多线程编程中使用列表可能是危险的,因为它不是线程安全的。

另一方面,deque要复杂一些,因为它的append()和pop()方法是原子性的,这意味着它们不会被其他线程中断。

我们可以使用deque构建多线程程序,但这可能会在将来引入一些复杂性。

现在的问题是,我们如何在Python堆栈中构建一个具有线程的程序。

答案是我们可以使用 LIFOqueue ,而我们知道LIFO代表的是后进先出。它使用put()和get()来添加和删除堆栈元素。

应该考虑哪种堆栈实现方法

我们已经提到了三种在Python中实现堆栈的方法。上述方法各自有其优点或缺点。

让我们澄清混淆;如果我们在线程中使用堆栈,您应该使用 Lifoqueue ,但要确保它在弹出和推入元素时的性能。但是,如果您不使用线程,请使用 deque

我们也可以使用列表来实现堆栈,但列表可能存在潜在的内存重新分配问题。列表和deque在接口上是相同的,但deque没有内存分配问题。

结论

我们简要介绍了堆栈及其实现方法。Python堆栈可以用于实际应用程序。我们可以根据需求选择实现方法。我们还定义了在线程环境中的Python堆栈。

Camera课程

Python教程

Java教程

Web教程

数据库教程

图形图像教程

办公软件教程

Linux教程

计算机教程

大数据教程

开发工具教程