栈(stack),又叫做堆栈,是一种容器,可存入数据元素、访问元素、删除元素,它的特点在于只能允许在容器的一端(称为栈顶指标,top)进行加入数据(push)和输出数据(pop)的运算。没有了位置概念,保证任何时候可以访问、删除的元素都是此前最后存入的元素,确定了一种默认的访问顺序。

由于栈数据结构只允许在一端进行操作,因而按照后进先出(LIFO,last in first out)的原理运行。

python怎么控制堆栈类存储空间大小 python堆和栈的概念_python

栈结构实现

线性表中的任何数据结构都可以实现栈。之前学的链表和顺序表都是线性表。
这里我们可以发现,顺序表和链表描述的是数据怎么存放,栈描述的是数据的操作。

栈的操作

• stack()创建一个新的空栈
• push(item)添加一个新的元素item到栈顶
• pop()弹出栈顶元素
• peek()返回栈顶元素
• is_empty()判断栈是否为空
• size()返回栈的元素个数

栈操作的具体实现

栈的属性也需要先初始化,选择一种容器(这里以列表为例)。首先,栈的内容容器是需要私有化的,因为我们不希望外部直接操作栈容器。随意选择从列表头部或者尾部添加元素。但是选中后,取元素也要在对应的端去取。
从时间复杂度来看,若采用顺序表来存储数据,则从头部添加元素时间复杂度是O(n),从尾部添加元素的时间复杂度是O(1)。因为从顺序表头部插入元素,涉及数据的搬迁,所以我们选择从尾部插入元素。若采用单链表来存储数据,则头插的时间复杂度为O(1),尾插时间复杂度为O(n),因为尾插需要遍历链表,所以选择头插法去进行存取。
因此说,实现栈的容器不同,为了时间复杂度最低,最终操作容器的数据端也是不同的。

class Stack(object):
    """栈"""
    def __init__(self):
        self.__list=[]#定义私有属性,用列表作为栈的容器
    def push(self,item):
        """添加一个新的元素item到栈顶"""
        self.__list.append(item)
    def pop(self):
        """弹出栈顶元素"""
        return self.__list.pop()
    def peek(self):
        """返回栈顶元素"""
        if self.__list:#空列表不支持-1操作,因此还需要对列表进行判断,如果列表存在且不为空才进行-1操作
            return self.__list[-1]
        else:
            return None
    def is_empty(self):
        """判断栈是否为空"""
        return self.__list==[]#为空的话就会返回True

    def size(self):
        """返回栈中元素个数"""
        return len(self.__list)
        #self.__list为空时,逻辑值是假。not self.__list返回真,在判空的函数中,返回真。因此return not self.__list也可以是实现判空

python基础知识中,空字符串、0、空字典、空元组、空列表都为假,逻辑判断可以直接判断
调用class类及其方法,首先要创建一个新的栈对象

if __name__=="__main__":
    s=Stack()
    s.push(1)
    s.push(2)
    s.push(3)
    s.push(4)
    print(s.pop())
    print(s.pop())
    print(s.pop())
    print(s.pop())

运行结果:

python怎么控制堆栈类存储空间大小 python堆和栈的概念_python_02


由此也证明了栈先进后出的特点。

队列

队列(queue)是只允许在一端进行插入操作,而在另一端进行删除操作的线性表。

队列是一种先进先出(first in first out)的线性表,简称FIFO。允许插入的一端为队尾,允许删除的一端为队头。队列不允许在中间部位进行操作。假设队列是q=(a1,a2,…an),那么a1就是队头元素,而an就是队尾元素。这样我们就可以删除时,总是从a1开始,而插入时,总是在队列最后。这样也比较符合我们通常生活中的习惯,排在第一个的优先出列,最后来的排在队伍的最后。

python怎么控制堆栈类存储空间大小 python堆和栈的概念_链表_03

队列的实现

队列同栈一样,队列也可以用顺序表或者链表来实现。

具体操作

• Queue()创建一个空的队列
• enqueue(item)往队列中添加一个item元素
• dequeue()从队列头部删除一个元素
• is_empty()判断一个队列是否为空
• size()返回队列的大小

同样以顺序表为例,构造函数首先要声明一个空的列表来存队列数据。

def __init__(self):
        self.__list=[]

在队列中添加元素,从头部和尾部添加数据的时间复杂度(头部添加,尾部弹出;尾部添加,头部弹出),不管选择哪一种出入队方式,时间复杂度都是一样的。那么如何徐那种合理的出入队方式,就要根据最常用的操作是出队还是入队来判断。如果出队频率大很多,那么就要减少出队的时间复杂度,选择尾部出队。否则,相反。

class Queue(object):
    """队列"""
    def __init__(self):
        self.__list=[]
    def enqueue(self,item):
        """往队列中添加一个item元素"""
        self.__list.append(item)#列表尾部插入元素
        self.__list.insert(0,item)#列表中指定在头部插入元素
    def dequeue(self):
        """从队列头部删除一个元素"""
        return self.__list.pop(0)#列表头部删除元素
        return self.__list.pop()#列表尾部删除元素
    def is_empty(self):
        """判断队列是否为空"""
        return self.__list==[]

    def size(self):
        """返回队列大小"""
        return len(self.__list)
if __name__=="__main__":
    q=Queue()
    q.enqueue(1)
    q.enqueue(2)
    q.enqueue(3)
    q.enqueue(4)
    print(q.dequeue())
    print(q.dequeue())
    print(q.dequeue())
    print(q.dequeue())

运行结果:

python怎么控制堆栈类存储空间大小 python堆和栈的概念_队列_04


证明了队列FIFO的I/O特点。

双端队列

双端队列(deque,全称double-ended queue),是一种觉有队列和栈的性质的数据结构。

双端队列中的元素可以从两端弹出,其限定插入和删除操作在表的两端进行。双端队列可以在队列任意一端入队和出队。

python怎么控制堆栈类存储空间大小 python堆和栈的概念_python怎么控制堆栈类存储空间大小_05

操作

• Deque()创建一个空的双端队列
• add_front(item)从队头加入一个item元素
• add_rear(item)从队尾加入一个item元素
• remove_front()从队头删除一个元素
• remove_rear()从队尾删除一个item元素
• is_empty()判断双端队列是否为空
• size()返回队列的大小

双端队列如果只考虑一端的进出,那就是栈的特性。

class Deque(object):
    """双端队列"""
    def __init__(self):
        self.__list=[]
    def add_front(self,item):
        """从队头加入item元素"""
        self.__list.insert(0,item)
    def add_rear(self,item):
        """从队尾加入item元素"""
        self.__list.append(item)
    def remove_front(self):
        """从队头删除元素"""
        return self.__list.pop(0)
    def remove_rear(self):
        """从队尾删除元素"""
        return self.__list.pop()
    def is_emoty(self):
        """判断队列是否为空"""
        return self.__list==[]
    def size(self):
        """返回队列的大小"""
        return len(self.__list)

定义的方法都是通用的,但是在不同场景下,不同的调用方式,会出现不同的结果。

if __name__=="__main__":
    dq=Deque()
    print("stack")
    dq.add_front(1)
    dq.add_front(2)
    dq.add_front(3)
    dq.add_front(4)
    print(dq.remove_front())
    print(dq.remove_front())
    print(dq.remove_front())
    print(dq.remove_front())#头部插入,头部删除,这里相当于栈
    print("queue")
    dq.add_front(1)
    dq.add_front(2)
    dq.add_front(3)
    dq.add_front(4)
    print(dq.remove_rear())
    print(dq.remove_rear())
    print(dq.remove_rear())
    print(dq.remove_rear())#头部插入,尾部删除,就相当于队列

运行结果:

python怎么控制堆栈类存储空间大小 python堆和栈的概念_python_06