栈(Stack)和队列(Queue)都是一种特殊的线性表。
为了模拟现实世界的规则,为普通的线性表增加了一些约束。这些约束可以使我们的操作安全,符合语义,符合语义的操作更方便。
原则
栈的基本思想是后进先出(LIFO),在计算机科学中被形式化,并被广泛应用于算法设计、操作系统、编程语言等领域。例如,函数调用的执行过程就是一个典型的栈结构,函数的调用和返回就对应着栈的压入和弹出操作。
它遵循先进先出(FIFO,First In First Out)的原则。就像我们在超市结账时排队一样,先到的人先结账,后到的人需要排在队伍的末尾等待。
栈和队列是一种强大而灵活的数据结构,它在许多不同类型的系统中都有广泛应用。理解和掌握栈和队列的概念可以帮助我们解决很多有趣的问题。
栈和队列的基本操作
栈的基本操作:
- Push(压入) :将一个元素放入栈的顶部。
- Pop(弹出) :移除栈顶的元素,并返回这个元素的值。
- Peek/Top(查看栈顶) :返回栈顶元素的值,但不移除这个元素。
- IsEmpty(判断栈是否为空) :如果栈内没有元素,返回True,否则返回False。
队列的基本操作:
- Enqueue(入队) :将一个元素添加到队列的末尾。
- Dequeue(出队) :移除队列头部的元素,并返回这个元素的值。
- Peek/Front(查看队头) :返回队列头部元素的值,但不移除这个元素。
- IsEmpty(判断队列是否为空) :如果队列内没有元素,返回True,否则返回False。
实现
这里需要强调,栈和队列是一种偏应用层的结构,从大分类上它是线性表,从实现上他可以使用数组方式【顺序存储】,也可以使用链表【链式存储】 。
另外栈和队列直接也可以相互实现,即利用栈实现队列,用队列实现栈。
栈的变种
- 单调栈
单调栈是一种特殊的栈结构,它的特点是栈内元素保持单调性,可以是单调递增也可以是单调递减。
单调栈常常用于解决一类与邻近元素关系相关的问题,例如寻找数组中每个元素的下一个更大元素或下一个更小元素。
以下是单调栈的基本操作:
- Push(压入) :在压入新元素时,会不断地将栈顶元素弹出,直到栈顶元素满足单调性要求,然后再将新元素压入栈中。例如,在单调递增栈中,如果新元素大于栈顶元素,就将栈顶元素弹出,直到栈顶元素小于新元素,然后再将新元素压入栈中。
- Pop(弹出) :移除栈顶的元素,并返回这个元素的值。
- Peek/Top(查看栈顶) :返回栈顶元素的值,但不移除这个元素。
- IsEmpty(判断栈是否为空) :如果栈内没有元素,返回True,否则返回False。
单调栈的一个重要应用是解决"下一个更大元素"或"下一个更小元素"的问题。例如,给定一个数组,找出数组中每个元素右边第一个比它大的元素。这类问题可以通过单调栈在O(n)的时间复杂度内解决。
队列的变种
- 双端队列
- 循环队列
循环队列(Circular Queue)是一种特殊的队列,特点是在物理结构上形成一个环(逻辑上的环),队尾的下一个位置就是队头。当队列满时,如果继续出队,就可以在队头的位置再次入队。这种操作方式充分利用了数组空间,避免了线性队列出队后导致的空间浪费。
值得注意的是队列判空,判满的条件
队列为空的判断条件为 head == tail
队列满的条件为 (tail+1)%n=head
- 优先级队列