栈 栈是一种遵循先入后出的逻辑的线性数据结构。如下图所示,我们把堆叠元素的顶部称为“栈顶”,底部称为“栈底”。将把元素添加到栈顶的操作叫做“入栈”,删除栈顶元素的操作叫做“出栈”。
栈常用操作 栈的常用操作如下表所示,具体的方法名需要根据所使用的编程语言来确定。在此,我们以常见的 push()、pop()、peek() 命名为例。
 表    栈的操作效率  
方法 
描述 
时间复杂度 
 
 
push() 
元素入栈(添加至栈顶) 
O(1) 
 
pop() 
栈顶元素出栈 
O(1) 
 
peek() 
访问栈顶元素 
O(1) 
 
Python:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 stack: list [int ] = [] stack.append(1 ) stack.append(3 ) stack.append(2 ) stack.append(5 ) stack.append(4 ) peek: int  = stack[-1 ] pop: int  = stack.pop() size: int  = len (stack) is_empty: bool  = len (stack) == 0  
 
 Go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 var  stack []int stack = append (stack, 1 ) stack = append (stack, 3 ) stack = append (stack, 2 ) stack = append (stack, 5 ) stack = append (stack, 4 ) peek := stack[len (stack)-1 ] pop := stack[len (stack)-1 ] stack = stack[:len (stack)-1 ] size := len (stack) isEmpty := len (stack) == 0  
 
栈的实现 栈遵循先入后出的原则,因此我们只能在栈顶添加或删除元素。然而,数组和链表都可以在任意位置添加和删除元素,因此栈可以被视为一种受限制的数组或链表 。
基于链表的实现 使用链表来实现栈时,我们可以将链表的头节点视为栈顶,尾节点视为栈底。
如下图所示,对于入栈操作,我们只需将元素插入链表头部,这种节点插入方法被称为“头插法”。而对于出栈操作,只需将头节点从链表中删除即可。
Python:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class  LinkedListStack :    """基于链表实现的栈"""      def  __init__ (self ):         """构造方法"""          self.__peek: ListNode | None  = None          self.__size: int  = 0      def  size (self ) -> int :         """获取栈的长度"""          return  self.__size     def  is_empty (self ) -> bool :         """判断栈是否为空"""          return  not  self.__peek     def  push (self, val: int  ):         """入栈"""          node = ListNode(val)         node.next  = self.__peek         self.__peek = node         self.__size += 1      def  pop (self ) -> int :         """出栈"""          num: int  = self.peek()         self.__peek = self.__peek.next          self.__size -= 1          return  num     def  peek (self ) -> int :         """访问栈顶元素"""                   if  not  self.__peek:             return  None          return  self.__peek.val     def  to_list (self ) -> list [int ]:         """转化为列表用于打印"""          arr = []         node = self.__peek         while  node:             arr.append(node.val)             node = node.next          arr.reverse()         return  arr 
 
Go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 type  linkedListStack struct  {         data *list.List } func  newLinkedListStack ()   *linkedListStack {    return  &linkedListStack{         data: list.New(),     } } func  (s *linkedListStack)   push(value int ) {    s.data.PushBack(value) } func  (s *linkedListStack)   pop() any {    if  s.isEmpty() {         return  nil      }     e := s.data.Back()     s.data.Remove(e)     return  e.Value } func  (s *linkedListStack)   peek() any {    if  s.isEmpty() {         return  nil      }     e := s.data.Back()     return  e.Value } func  (s *linkedListStack)   size() int  {    return  s.data.Len() } func  (s *linkedListStack)   isEmpty() bool  {    return  s.data.Len() == 0  } func  (s *linkedListStack)   toList() *list.List {    return  s.data } 
 
基于数组的实现 使用数组实现栈时,我们可以将数组的尾部作为栈顶。如下图所示,入栈与出栈操作分别对应在数组尾部添加元素与删除元素,时间复杂度都为 O(1)。
由于入栈的元素可能会源源不断地增加,因此我们可以使用动态数组,这样就无须自行处理数组扩容问题。
Python:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class  ArrayStack :    """基于数组实现的栈"""      def  __init__ (self ):         """构造方法"""          self.__stack: list [int ] = []     def  size (self ) -> int :         """获取栈的长度"""          return  len (self.__stack)     def  is_empty (self ) -> bool :         """判断栈是否为空"""          return  self.__stack == []     def  push (self, item: int  ):         """入栈"""          self.__stack.append(item)     def  pop (self ) -> int :         """出栈"""          if  self.is_empty():             raise  IndexError("栈为空" )         return  self.__stack.pop()     def  peek (self ) -> int :         """访问栈顶元素"""          if  self.is_empty():             raise  IndexError("栈为空" )         return  self.__stack[-1 ]     def  to_list (self ) -> list [int ]:         """返回列表用于打印"""          return  self.__stack 
 
Go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 type  arrayStack struct  {    data []int   } func  newArrayStack ()   *arrayStack {    return  &arrayStack{                  data: make ([]int , 0 , 16 ),     } } func  (s *arrayStack)   size() int  {    return  len (s.data) } func  (s *arrayStack)   isEmpty() bool  {    return  s.size() == 0  } func  (s *arrayStack)   push(v int ) {         s.data = append (s.data, v) } func  (s *arrayStack)   pop() any {    val := s.peek()     s.data = s.data[:len (s.data)-1 ]     return  val } func  (s *arrayStack)   peek() any {    if  s.isEmpty() {         return  nil      }     val := s.data[len (s.data)-1 ]     return  val } func  (s *arrayStack)   toSlice() []int  {    return  s.data } 
 
两种实现对比 支持操作 
两种实现都支持栈定义中的各项操作。数组实现额外支持随机访问,但这已超出了栈的定义范畴,因此一般不会用到。
时间效率 
在基于数组的实现中,入栈和出栈操作都是在预先分配好的连续内存中进行,具有很好的缓存本地性,因此效率较高。然而,如果入栈时超出数组容量,会触发扩容机制,导致该次入栈操作的时间复杂度变为 O(n) 。
在链表实现中,链表的扩容非常灵活,不存在上述数组扩容时效率降低的问题。但是,入栈操作需要初始化节点对象并修改指针,因此效率相对较低。不过,如果入栈元素本身就是节点对象,那么可以省去初始化步骤,从而提高效率。
综上所述,当入栈与出栈操作的元素是基本数据类型时,例如 int 或 double ,我们可以得出以下结论。
基于数组实现的栈在触发扩容时效率会降低,但由于扩容是低频操作,因此平均效率更高。 
基于链表实现的栈可以提供更加稳定的效率表现。 
 
空间效率 
在初始化列表时,系统会为列表分配“初始容量”,该容量可能超过实际需求。并且,扩容机制通常是按照特定倍率(例如 2 倍)进行扩容,扩容后的容量也可能超出实际需求。因此,基于数组实现的栈可能造成一定的空间浪费 。
然而,由于链表节点需要额外存储指针,因此链表节点占用的空间相对较大 。
综上,我们不能简单地确定哪种实现更加节省内存,需要针对具体情况进行分析。
栈典型应用 
浏览器中的后退与前进、软件中的撤销与反撤销 。每当我们打开新的网页,浏览器就会将上一个网页执行入栈,这样我们就可以通过后退操作回到上一页面。后退操作实际上是在执行出栈。如果要同时支持后退和前进,那么需要两个栈来配合实现。 
程序内存管理 。每次调用函数时,系统都会在栈顶添加一个栈帧,用于记录函数的上下文信息。在递归函数中,向下递推阶段会不断执行入栈操作,而向上回溯阶段则会执行出栈操作。 
 
队列 队列是一种遵循先入先出规则的线性数据结构。顾名思义,队列模拟了排队现象,即新来的人不断加入队列的尾部,而位于队列头部的人逐个离开。
如下图所示,我们将队列的头部称为“队首”,尾部称为“队尾”,将把元素加入队尾的操作称为“入队”,删除队首元素的操作称为“出队”。
队列常用操作  表    队列操作效率  
方法名 
描述 
时间复杂度 
 
 
push() 
元素入队,即将元素添加至队尾 
O(1) 
 
pop() 
队首元素出队 
O(1) 
 
peek() 
访问队首元素 
O(1) 
 
Python:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 que: deque[int ] = collections.deque() que.append(1 ) que.append(3 ) que.append(2 ) que.append(5 ) que.append(4 ) front: int  = que[0 ]; pop: int  = que.popleft() size: int  = len (que) is_empty: bool  = len (que) == 0  
 
Go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 queue := list.New() queue.PushBack(1 ) queue.PushBack(3 ) queue.PushBack(2 ) queue.PushBack(5 ) queue.PushBack(4 ) peek := queue.Front() pop := queue.Front() queue.Remove(pop) size := queue.Len() isEmpty := queue.Len() == 0  
 
队列实现 基于链表的实现 如下图所示,我们可以将链表的“头节点”和“尾节点”分别视为“队首”和“队尾”,规定队尾仅可添加节点,队首仅可删除节点。
Python:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 class  LinkedListQueue :    """基于链表实现的队列"""      def  __init__ (self ):         """构造方法"""          self.__front: ListNode | None  = None            self.__rear: ListNode | None  = None            self.__size: int  = 0      def  size (self ) -> int :         """获取队列的长度"""          return  self.__size     def  is_empty (self ) -> bool :         """判断队列是否为空"""          return  not  self.__front     def  push (self, num: int  ):         """入队"""                   node = ListNode(num)                  if  self.__front is  None :             self.__front = node             self.__rear = node                  else :             self.__rear.next  = node             self.__rear = node         self.__size += 1      def  pop (self ) -> int :         """出队"""          num = self.peek()                  self.__front = self.__front.next          self.__size -= 1          return  num     def  peek (self ) -> int :         """访问队首元素"""          if  self.size() == 0 :             print ("队列为空" )             return  False          return  self.__front.val     def  to_list (self ) -> list [int ]:         """转化为列表用于打印"""          queue = []         temp = self.__front         while  temp:             queue.append(temp.val)             temp = temp.next          return  queue 
 
Go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 type  linkedListQueue struct  {         data *list.List } func  newLinkedListQueue ()   *linkedListQueue {    return  &linkedListQueue{         data: list.New(),     } } func  (s *linkedListQueue)   push(value any) {    s.data.PushBack(value) } func  (s *linkedListQueue)   pop() any {    if  s.isEmpty() {         return  nil      }     e := s.data.Front()     s.data.Remove(e)     return  e.Value } func  (s *linkedListQueue)   peek() any {    if  s.isEmpty() {         return  nil      }     e := s.data.Front()     return  e.Value } func  (s *linkedListQueue)   size() int  {    return  s.data.Len() } func  (s *linkedListQueue)   isEmpty() bool  {    return  s.data.Len() == 0  } func  (s *linkedListQueue)   toList() *list.List {    return  s.data } 
 
基于数组的实现 由于数组删除首元素的时间复杂度为O(n),这会导致出队操作效率较低。然而,我们可以采用以下巧妙方法来避免这个问题。
我们可以使用一个变量 front 指向队首元素的索引,并维护一个变量 size 用于记录队列长度。定义 rear = front + size ,这个公式计算出的 rear 指向队尾元素之后的下一个位置。
基于此设计,**数组中包含元素的有效区间为 [front, rear - 1]**,各种操作的实现方法如下图所示。
入队操作:将输入元素赋值给 rear 索引处,并将 size 增加 1 。 
出队操作:只需将 front 增加 1 ,并将 size 减少 1 。 
 
可以看到,入队和出队操作都只需进行一次操作,时间复杂度均为 O(1) 。
你可能会发现一个问题:在不断进行入队和出队的过程中,front 和 rear 都在向右移动,当它们到达数组尾部时就无法继续移动了 。为解决此问题,我们可以将数组视为首尾相接的“环形数组”。
对于环形数组,我们需要让 front 或 rear 在越过数组尾部时,直接回到数组头部继续遍历。这种周期性规律可以通过“取余操作”来实现,代码如下所示。
Python:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 class  ArrayQueue :    """基于环形数组实现的队列"""      def  __init__ (self, size: int  ):         """构造方法"""          self.__nums: list [int ] = [0 ] * size           self.__front: int  = 0            self.__size: int  = 0        def  capacity (self ) -> int :         """获取队列的容量"""          return  len (self.__nums)     def  size (self ) -> int :         """获取队列的长度"""          return  self.__size     def  is_empty (self ) -> bool :         """判断队列是否为空"""          return  self.__size == 0      def  push (self, num: int  ):         """入队"""          if  self.__size == self.capacity():             raise  IndexError("队列已满" )                           rear: int  = (self.__front + self.__size) % self.capacity()                  self.__nums[rear] = num         self.__size += 1      def  pop (self ) -> int :         """出队"""          num: int  = self.peek()                  self.__front = (self.__front + 1 ) % self.capacity()         self.__size -= 1          return  num     def  peek (self ) -> int :         """访问队首元素"""          if  self.is_empty():             raise  IndexError("队列为空" )         return  self.__nums[self.__front]     def  to_list (self ) -> list [int ]:         """返回列表用于打印"""          res = [0 ] * self.size()         j: int  = self.__front         for  i in  range (self.size()):             res[i] = self.__nums[(j % self.capacity())]             j += 1          return  res 
 
Go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 type  arrayQueue struct  {    nums        []int       front       int         queSize     int         queCapacity int     } func  newArrayQueue (queCapacity int )   *arrayQueue {    return  &arrayQueue{         nums:        make ([]int , queCapacity),         queCapacity: queCapacity,         front:       0 ,         queSize:     0 ,     } } func  (q *arrayQueue)   size() int  {    return  q.queSize } func  (q *arrayQueue)   isEmpty() bool  {    return  q.queSize == 0  } func  (q *arrayQueue)   push(num int ) {         if  q.queSize == q.queCapacity {         return      }               rear := (q.front + q.queSize) % q.queCapacity          q.nums[rear] = num     q.queSize++ } func  (q *arrayQueue)   pop() any {    num := q.peek()          q.front = (q.front + 1 ) % q.queCapacity     q.queSize--     return  num } func  (q *arrayQueue)   peek() any {    if  q.isEmpty() {         return  nil      }     return  q.nums[q.front] } func  (q *arrayQueue)   toSlice() []int  {    rear := (q.front + q.queSize)     if  rear >= q.queCapacity {         rear %= q.queCapacity         return  append (q.nums[q.front:], q.nums[:rear]...)     }     return  q.nums[q.front:rear] } 
 
以上实现的队列仍然具有局限性,即其长度不可变。然而,这个问题不难解决,我们可以将数组替换为动态数组,从而引入扩容机制。
两种实现的对比结论与栈一致。
队列典型应用 
淘宝订单 。购物者下单后,订单将加入队列中,系统随后会根据顺序依次处理队列中的订单。在双十一期间,短时间内会产生海量订单,高并发成为工程师们需要重点攻克的问题。 
各类待办事项 。任何需要实现“先来后到”功能的场景,例如打印机的任务队列、餐厅的出餐队列等。队列在这些场景中可以有效地维护处理顺序。 
 
双向队列 在队列中,我们仅能在头部删除或在尾部添加元素。双向队列提供了更高的灵活性,允许在头部和尾部执行元素的添加或删除操作。
双向队列常用操作 双向队列的常用操作如下表所示,具体的方法名称需要根据所使用的编程语言来确定。
 表    双向队列操作效率  
方法名 
描述 
时间复杂度 
 
 
pushFirst() 
将元素添加至队首 
O(1) 
 
pushLast() 
将元素添加至队尾 
O(1) 
 
popFirst() 
删除队首元素 
O(1) 
 
popLast() 
删除队尾元素 
O(1) 
 
peekFirst() 
访问队首元素 
O(1) 
 
peekLast() 
访问队尾元素 
O(1) 
 
我们可以直接使用编程语言中已实现的双向队列类。
Python:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 deque: deque[int ] = collections.deque() deque.append(2 )       deque.append(5 ) deque.append(4 ) deque.appendleft(3 )   deque.appendleft(1 ) front: int  = deque[0 ]   rear: int  = deque[-1 ]   pop_front: int  = deque.popleft()   pop_rear: int  = deque.pop()        size: int  = len (deque) is_empty: bool  = len (deque) == 0  
 
 Go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 deque := list.New() deque.PushBack(2 )       deque.PushBack(5 ) deque.PushBack(4 ) deque.PushFront(3 )      deque.PushFront(1 ) front := deque.Front()  rear := deque.Back()    deque.Remove(front)     deque.Remove(rear)      size := deque.Len() isEmpty := deque.Len() == 0  
 
双向队列实现 双向队列的实现与队列类似,可以选择链表或数组作为底层数据结构。
基于双向链表的实现 采用“双向链表”作为双向队列的底层数据结构。如下图所示,我们将双向链表的头节点和尾节点视为双向队列的队首和队尾,同时实现在两端添加和删除节点的功能。
Python:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 class  ListNode :    """双向链表节点"""      def  __init__ (self, val: int  ):         """构造方法"""          self.val: int  = val         self.next : ListNode | None  = None            self.prev: ListNode | None  = None    class  LinkedListDeque :    """基于双向链表实现的双向队列"""      def  __init__ (self ):         """构造方法"""          self.front: ListNode | None  = None            self.rear: ListNode | None  = None            self.__size: int  = 0        def  size (self ) -> int :         """获取双向队列的长度"""          return  self.__size     def  is_empty (self ) -> bool :         """判断双向队列是否为空"""          return  self.size() == 0      def  push (self, num: int , is_front: bool  ):         """入队操作"""          node = ListNode(num)                  if  self.is_empty():             self.front = self.rear = node                  elif  is_front:                          self.front.prev = node             node.next  = self.front             self.front = node                    else :                          self.rear.next  = node             node.prev = self.rear             self.rear = node           self.__size += 1        def  push_first (self, num: int  ):         """队首入队"""          self.push(num, True )     def  push_last (self, num: int  ):         """队尾入队"""          self.push(num, False )     def  pop (self, is_front: bool  ) -> int :         """出队操作"""                   if  self.is_empty():             return  None                   if  is_front:             val: int  = self.front.val                            fnext: ListNode | None  = self.front.next              if  fnext != None :                 fnext.prev = None                  self.front.next  = None              self.front = fnext                    else :             val: int  = self.rear.val                            rprev: ListNode | None  = self.rear.prev             if  rprev != None :                 rprev.next  = None                  self.rear.prev = None              self.rear = rprev           self.__size -= 1            return  val     def  pop_first (self ) -> int :         """队首出队"""          return  self.pop(True )     def  pop_last (self ) -> int :         """队尾出队"""          return  self.pop(False )     def  peek_first (self ) -> int :         """访问队首元素"""          return  None  if  self.is_empty() else  self.front.val     def  peek_last (self ) -> int :         """访问队尾元素"""          return  None  if  self.is_empty() else  self.rear.val     def  to_array (self ) -> list [int ]:         """返回数组用于打印"""          node = self.front         res = [0 ] * self.size()         for  i in  range (self.size()):             res[i] = node.val             node = node.next          return  res 
 
Go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 type  linkedListDeque struct  {         data *list.List } func  newLinkedListDeque ()   *linkedListDeque {    return  &linkedListDeque{         data: list.New(),     } } func  (s *linkedListDeque)   pushFirst(value any) {    s.data.PushFront(value) } func  (s *linkedListDeque)   pushLast(value any) {    s.data.PushBack(value) } func  (s *linkedListDeque)   popFirst() any {    if  s.isEmpty() {         return  nil      }     e := s.data.Front()     s.data.Remove(e)     return  e.Value } func  (s *linkedListDeque)   popLast() any {    if  s.isEmpty() {         return  nil      }     e := s.data.Back()     s.data.Remove(e)     return  e.Value } func  (s *linkedListDeque)   peekFirst() any {    if  s.isEmpty() {         return  nil      }     e := s.data.Front()     return  e.Value } func  (s *linkedListDeque)   peekLast() any {    if  s.isEmpty() {         return  nil      }     e := s.data.Back()     return  e.Value } func  (s *linkedListDeque)   size() int  {    return  s.data.Len() } func  (s *linkedListDeque)   isEmpty() bool  {    return  s.data.Len() == 0  } func  (s *linkedListDeque)   toList() *list.List {    return  s.data } 
 
基于数组的实现 如下图所示,与基于数组实现队列类似,我们也可以使用环形数组来实现双向队列。
在队列的实现基础上,仅需增加“队首入队”和“队尾出队”的方法。
Python:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 class  ArrayDeque :    """基于环形数组实现的双向队列"""      def  __init__ (self, capacity: int  ):         """构造方法"""          self.__nums: list [int ] = [0 ] * capacity         self.__front: int  = 0          self.__size: int  = 0      def  capacity (self ) -> int :         """获取双向队列的容量"""          return  len (self.__nums)     def  size (self ) -> int :         """获取双向队列的长度"""          return  self.__size     def  is_empty (self ) -> bool :         """判断双向队列是否为空"""          return  self.__size == 0      def  index (self, i: int  ) -> int :         """计算环形数组索引"""                                     return  (i + self.capacity()) % self.capacity()     def  push_first (self, num: int  ):         """队首入队"""          if  self.__size == self.capacity():             print ("双向队列已满" )             return                            self.__front = self.index(self.__front - 1 )                  self.__nums[self.__front] = num         self.__size += 1      def  push_last (self, num: int  ):         """队尾入队"""          if  self.__size == self.capacity():             print ("双向队列已满" )             return                   rear = self.index(self.__front + self.__size)                  self.__nums[rear] = num         self.__size += 1      def  pop_first (self ) -> int :         """队首出队"""          num = self.peek_first()                  self.__front = self.index(self.__front + 1 )         self.__size -= 1          return  num     def  pop_last (self ) -> int :         """队尾出队"""          num = self.peek_last()         self.__size -= 1          return  num     def  peek_first (self ) -> int :         """访问队首元素"""          if  self.is_empty():             raise  IndexError("双向队列为空" )         return  self.__nums[self.__front]     def  peek_last (self ) -> int :         """访问队尾元素"""          if  self.is_empty():             raise  IndexError("双向队列为空" )                  last = self.index(self.__front + self.__size - 1 )         return  self.__nums[last]     def  to_array (self ) -> list [int ]:         """返回数组用于打印"""                   res = []         for  i in  range (self.__size):             res.append(self.__nums[self.index(self.__front + i)])         return  res 
 
Go:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 type  arrayDeque struct  {    nums        []int       front       int         queSize     int         queCapacity int     } func  newArrayDeque (queCapacity int )   *arrayDeque {    return  &arrayDeque{         nums:        make ([]int , queCapacity),         queCapacity: queCapacity,         front:       0 ,         queSize:     0 ,     } } func  (q *arrayDeque)   size() int  {    return  q.queSize } func  (q *arrayDeque)   isEmpty() bool  {    return  q.queSize == 0  } func  (q *arrayDeque)   index(i int ) int  {                   return  (i + q.queCapacity) % q.queCapacity } func  (q *arrayDeque)   pushFirst(num int ) {    if  q.queSize == q.queCapacity {         fmt.Println("双向队列已满" )         return      }               q.front = q.index(q.front - 1 )          q.nums[q.front] = num     q.queSize++ } func  (q *arrayDeque)   pushLast(num int ) {    if  q.queSize == q.queCapacity {         fmt.Println("双向队列已满" )         return      }          rear := q.index(q.front + q.queSize)          q.nums[rear] = num     q.queSize++ } func  (q *arrayDeque)   popFirst() any {    num := q.peekFirst()          q.front = q.index(q.front + 1 )     q.queSize--     return  num } func  (q *arrayDeque)   popLast() any {    num := q.peekLast()     q.queSize--     return  num } func  (q *arrayDeque)   peekFirst() any {    if  q.isEmpty() {         return  nil      }     return  q.nums[q.front] } func  (q *arrayDeque)   peekLast() any {    if  q.isEmpty() {         return  nil      }          last := q.index(q.front + q.queSize - 1 )     return  q.nums[last] } func  (q *arrayDeque)   toSlice() []int  {         res := make ([]int , q.queSize)     for  i, j := 0 , q.front; i < q.queSize; i++ {         res[i] = q.nums[q.index(j)]         j++     }     return  res } 
 
双向队列应用 双向队列兼具栈与队列的逻辑,因此它可以实现这两者的所有应用场景,同时提供更高的自由度 。
我们知道,软件的“撤销”功能通常使用栈来实现:系统将每次更改操作 push 到栈中,然后通过 pop 实现撤销。然而,考虑到系统资源的限制,软件通常会限制撤销的步数(例如仅允许保存50步)。当栈的长度超过50时,软件需要在栈底(即队首)执行删除操作。但栈无法实现该功能,此时就需要使用双向队列来替代栈 。请注意,“撤销”的核心逻辑仍然遵循栈的先入后出原则,只是双向队列能够更加灵活地实现一些额外逻辑。
References:https://www.hello-algo.com/chapter_stack_and_queue/