📜  Python中的Stack

📅  最后修改于: 2020-10-29 01:21:49             🧑  作者: Mango

用Python 堆栈

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

什么是堆栈?

堆栈是一种线性数据结构,其中数据按对象排列在另一个堆栈上。它以LIFO(后进先出)的方式存储数据。数据的存储顺序与板在厨房中一个接一个地排列一样。堆栈的简单示例是编辑器中的“撤消”功能。撤消功能适用于我们完成的最后一个事件。

我们总是从盘子堆中挑选最后一块盘子。在堆栈中,新元素插入到一端,而一个元素只能移到该端。

我们可以在堆栈中执行两个操作-PUSH和POP。 PUSH操作是在添加元素时,POP操作是在从堆栈中删除元素时。

堆栈方法

Python提供了以下堆栈常用的方法。

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

堆栈的实现

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

我们可以通过以下方式在Python中实现堆栈。

  • 清单
  • 出队
  • 生命队列

使用清单实施

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 
    print(my_stack.pop())
IndexError: pop from empty list

说明-

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

使用collection.deque实现

收集模块提供了双端队列类,该类用于创建Python堆栈。双端队列发音为“ deck”,意思是“双端队列”。由于双端队列比列表更快速地执行附加和弹出操作,因此可以优先于列表。时间复杂度为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([])

说明:

上面的代码几乎与前面的示例相似。但是,唯一的区别是,我们已从收集模块中导入了双端队列。

双端队列清单

该列表将元素紧挨着存储,并使用连续的内存。这对于几种操作(例如索引到列表)最有效。例如-由于Python知道特定元素的确切位置,因此获取list1 [2]很快。连续的内存还允许切片在列表上正常工作。

该列表比另一些对象花费更多的时间来append()一些对象。如果连续内存块已满,它将获得另一个块,该块可能比正常的append()函数花费更长的时间。

使用队列模块实现

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

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

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

让我们了解以下队列模块示例。

范例-

# 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

说明-

在上面,我们导入了队列模块LIFOqueue。它的工作原理与堆栈相同,但是此模块包括上述一些其他功能。我们使用maxsize定义了一个堆栈,这意味着它最多可以容纳五个值。

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

Python堆栈和线程

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

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

另一方面,双端队列有点复杂,因为它的append()和pop()方法是原子的,这意味着它们不会被其他线程中断。

我们可以使用双端队列来构建多线程程序,但是将来可能不会引起什么复杂性。

现在出现了一个问题,我们如何构建带有线程的Python堆栈程序。

答案是,我们可以使用LIFOqueue,并且知道LIFO代表什么-后进先出。它使用put()和gets()添加和删除堆栈元素。

应该考虑哪种堆栈实现?

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

让我们消除混乱;我们在堆栈中使用线程,您应该使用Lifoqueue,但要确保其弹出和推送元素的性能。但是,如果您不使用线程,请使用双端队列。

我们还可以使用列表来实现堆栈,但是列表可能存在潜在的内存重新分配问题。列表和双端队列在界面上是相同的,但是双端队列没有内存分配问题。

结论

我们已经简要定义了一个堆栈及其实现。 Python堆栈可用于现实程序中。我们可以根据自己的要求选择实施方法。我们还定义了带有线程环境的Python堆栈。