--- comments: true --- # 5.1   栈 栈(stack)是一种遵循先入后出逻辑的线性数据结构。 我们可以将栈类比为桌面上的一摞盘子,如果想取出底部的盘子,则需要先将上面的盘子依次移走。我们将盘子替换为各种类型的元素(如整数、字符、对象等),就得到了栈这种数据结构。 如图 5-1 所示,我们把堆叠元素的顶部称为“栈顶”,底部称为“栈底”。将把元素添加到栈顶的操作叫作“入栈”,删除栈顶元素的操作叫作“出栈”。 ![栈的先入后出规则](stack.assets/stack_operations.png){ class="animation-figure" }

图 5-1   栈的先入后出规则

## 5.1.1   栈的常用操作 栈的常用操作如表 5-1 所示,具体的方法名需要根据所使用的编程语言来确定。在此,我们以常见的 `push()`、`pop()`、`peek()` 命名为例。

表 5-1   栈的操作效率

| 方法 | 描述 | 时间复杂度 | | -------- | ---------------------- | ---------- | | `push()` | 元素入栈(添加至栈顶) | $O(1)$ | | `pop()` | 栈顶元素出栈 | $O(1)$ | | `peek()` | 访问栈顶元素 | $O(1)$ |
通常情况下,我们可以直接使用编程语言内置的栈类。然而,某些语言可能没有专门提供栈类,这时我们可以将该语言的“数组”或“链表”当作栈来使用,并在程序逻辑上忽略与栈无关的操作。 === "Python" ```python title="stack.py" # 初始化栈 # Python 没有内置的栈类,可以把 list 当作栈来使用 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 ``` === "C++" ```cpp title="stack.cpp" /* 初始化栈 */ stack stack; /* 元素入栈 */ stack.push(1); stack.push(3); stack.push(2); stack.push(5); stack.push(4); /* 访问栈顶元素 */ int top = stack.top(); /* 元素出栈 */ stack.pop(); // 无返回值 /* 获取栈的长度 */ int size = stack.size(); /* 判断是否为空 */ bool empty = stack.empty(); ``` === "Java" ```java title="stack.java" /* 初始化栈 */ Stack stack = new Stack<>(); /* 元素入栈 */ stack.push(1); stack.push(3); stack.push(2); stack.push(5); stack.push(4); /* 访问栈顶元素 */ int peek = stack.peek(); /* 元素出栈 */ int pop = stack.pop(); /* 获取栈的长度 */ int size = stack.size(); /* 判断是否为空 */ boolean isEmpty = stack.isEmpty(); ``` === "C#" ```csharp title="stack.cs" /* 初始化栈 */ Stack stack = new(); /* 元素入栈 */ stack.Push(1); stack.Push(3); stack.Push(2); stack.Push(5); stack.Push(4); /* 访问栈顶元素 */ int peek = stack.Peek(); /* 元素出栈 */ int pop = stack.Pop(); /* 获取栈的长度 */ int size = stack.Count; /* 判断是否为空 */ bool isEmpty = stack.Count == 0; ``` === "Go" ```go title="stack_test.go" /* 初始化栈 */ // 在 Go 中,推荐将 Slice 当作栈来使用 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 ``` === "Swift" ```swift title="stack.swift" /* 初始化栈 */ // Swift 没有内置的栈类,可以把 Array 当作栈来使用 var stack: [Int] = [] /* 元素入栈 */ stack.append(1) stack.append(3) stack.append(2) stack.append(5) stack.append(4) /* 访问栈顶元素 */ let peek = stack.last! /* 元素出栈 */ let pop = stack.removeLast() /* 获取栈的长度 */ let size = stack.count /* 判断是否为空 */ let isEmpty = stack.isEmpty ``` === "JS" ```javascript title="stack.js" /* 初始化栈 */ // JavaScript 没有内置的栈类,可以把 Array 当作栈来使用 const stack = []; /* 元素入栈 */ stack.push(1); stack.push(3); stack.push(2); stack.push(5); stack.push(4); /* 访问栈顶元素 */ const peek = stack[stack.length-1]; /* 元素出栈 */ const pop = stack.pop(); /* 获取栈的长度 */ const size = stack.length; /* 判断是否为空 */ const is_empty = stack.length === 0; ``` === "TS" ```typescript title="stack.ts" /* 初始化栈 */ // TypeScript 没有内置的栈类,可以把 Array 当作栈来使用 const stack: number[] = []; /* 元素入栈 */ stack.push(1); stack.push(3); stack.push(2); stack.push(5); stack.push(4); /* 访问栈顶元素 */ const peek = stack[stack.length - 1]; /* 元素出栈 */ const pop = stack.pop(); /* 获取栈的长度 */ const size = stack.length; /* 判断是否为空 */ const is_empty = stack.length === 0; ``` === "Dart" ```dart title="stack.dart" /* 初始化栈 */ // Dart 没有内置的栈类,可以把 List 当作栈来使用 List stack = []; /* 元素入栈 */ stack.add(1); stack.add(3); stack.add(2); stack.add(5); stack.add(4); /* 访问栈顶元素 */ int peek = stack.last; /* 元素出栈 */ int pop = stack.removeLast(); /* 获取栈的长度 */ int size = stack.length; /* 判断是否为空 */ bool isEmpty = stack.isEmpty; ``` === "Rust" ```rust title="stack.rs" /* 初始化栈 */ // 把 Vec 当作栈来使用 let mut stack: Vec = Vec::new(); /* 元素入栈 */ stack.push(1); stack.push(3); stack.push(2); stack.push(5); stack.push(4); /* 访问栈顶元素 */ let top = stack.last().unwrap(); /* 元素出栈 */ let pop = stack.pop().unwrap(); /* 获取栈的长度 */ let size = stack.len(); /* 判断是否为空 */ let is_empty = stack.is_empty(); ``` === "C" ```c title="stack.c" // C 未提供内置栈 ``` === "Kotlin" ```kotlin title="stack.kt" /* 初始化栈 */ val stack = Stack() /* 元素入栈 */ stack.push(1) stack.push(3) stack.push(2) stack.push(5) stack.push(4) /* 访问栈顶元素 */ val peek = stack.peek() /* 元素出栈 */ val pop = stack.pop() /* 获取栈的长度 */ val size = stack.size /* 判断是否为空 */ val isEmpty = stack.isEmpty() ``` === "Ruby" ```ruby title="stack.rb" # 初始化栈 # Ruby 没有内置的栈类,可以把 Array 当作栈来使用 stack = [] # 元素入栈 stack << 1 stack << 3 stack << 2 stack << 5 stack << 4 # 访问栈顶元素 peek = stack.last # 元素出栈 pop = stack.pop # 获取栈的长度 size = stack.length # 判断是否为空 is_empty = stack.empty? ``` === "Zig" ```zig title="stack.zig" ``` ??? pythontutor "可视化运行"
## 5.1.2   栈的实现 为了深入了解栈的运行机制,我们来尝试自己实现一个栈类。 栈遵循先入后出的原则,因此我们只能在栈顶添加或删除元素。然而,数组和链表都可以在任意位置添加和删除元素,**因此栈可以视为一种受限制的数组或链表**。换句话说,我们可以“屏蔽”数组或链表的部分无关操作,使其对外表现的逻辑符合栈的特性。 ### 1.   基于链表的实现 使用链表实现栈时,我们可以将链表的头节点视为栈顶,尾节点视为栈底。 如图 5-2 所示,对于入栈操作,我们只需将元素插入链表头部,这种节点插入方法被称为“头插法”。而对于出栈操作,只需将头节点从链表中删除即可。 === "LinkedListStack" ![基于链表实现栈的入栈出栈操作](stack.assets/linkedlist_stack_step1.png){ class="animation-figure" } === "push()" ![linkedlist_stack_push](stack.assets/linkedlist_stack_step2_push.png){ class="animation-figure" } === "pop()" ![linkedlist_stack_pop](stack.assets/linkedlist_stack_step3_pop.png){ class="animation-figure" }

图 5-2   基于链表实现栈的入栈出栈操作

以下是基于链表实现栈的示例代码: === "Python" ```python title="linkedlist_stack.py" 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 self._size == 0 def push(self, val: int): """入栈""" node = ListNode(val) node.next = self._peek self._peek = node self._size += 1 def pop(self) -> int: """出栈""" num = self.peek() self._peek = self._peek.next self._size -= 1 return num def peek(self) -> int: """访问栈顶元素""" if self.is_empty(): raise IndexError("栈为空") 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 ``` === "C++" ```cpp title="linkedlist_stack.cpp" /* 基于链表实现的栈 */ class LinkedListStack { private: ListNode *stackTop; // 将头节点作为栈顶 int stkSize; // 栈的长度 public: LinkedListStack() { stackTop = nullptr; stkSize = 0; } ~LinkedListStack() { // 遍历链表删除节点,释放内存 freeMemoryLinkedList(stackTop); } /* 获取栈的长度 */ int size() { return stkSize; } /* 判断栈是否为空 */ bool isEmpty() { return size() == 0; } /* 入栈 */ void push(int num) { ListNode *node = new ListNode(num); node->next = stackTop; stackTop = node; stkSize++; } /* 出栈 */ int pop() { int num = top(); ListNode *tmp = stackTop; stackTop = stackTop->next; // 释放内存 delete tmp; stkSize--; return num; } /* 访问栈顶元素 */ int top() { if (isEmpty()) throw out_of_range("栈为空"); return stackTop->val; } /* 将 List 转化为 Array 并返回 */ vector toVector() { ListNode *node = stackTop; vector res(size()); for (int i = res.size() - 1; i >= 0; i--) { res[i] = node->val; node = node->next; } return res; } }; ``` === "Java" ```java title="linkedlist_stack.java" /* 基于链表实现的栈 */ class LinkedListStack { private ListNode stackPeek; // 将头节点作为栈顶 private int stkSize = 0; // 栈的长度 public LinkedListStack() { stackPeek = null; } /* 获取栈的长度 */ public int size() { return stkSize; } /* 判断栈是否为空 */ public boolean isEmpty() { return size() == 0; } /* 入栈 */ public void push(int num) { ListNode node = new ListNode(num); node.next = stackPeek; stackPeek = node; stkSize++; } /* 出栈 */ public int pop() { int num = peek(); stackPeek = stackPeek.next; stkSize--; return num; } /* 访问栈顶元素 */ public int peek() { if (isEmpty()) throw new IndexOutOfBoundsException(); return stackPeek.val; } /* 将 List 转化为 Array 并返回 */ public int[] toArray() { ListNode node = stackPeek; int[] res = new int[size()]; for (int i = res.length - 1; i >= 0; i--) { res[i] = node.val; node = node.next; } return res; } } ``` === "C#" ```csharp title="linkedlist_stack.cs" /* 基于链表实现的栈 */ class LinkedListStack { ListNode? stackPeek; // 将头节点作为栈顶 int stkSize = 0; // 栈的长度 public LinkedListStack() { stackPeek = null; } /* 获取栈的长度 */ public int Size() { return stkSize; } /* 判断栈是否为空 */ public bool IsEmpty() { return Size() == 0; } /* 入栈 */ public void Push(int num) { ListNode node = new(num) { next = stackPeek }; stackPeek = node; stkSize++; } /* 出栈 */ public int Pop() { int num = Peek(); stackPeek = stackPeek!.next; stkSize--; return num; } /* 访问栈顶元素 */ public int Peek() { if (IsEmpty()) throw new Exception(); return stackPeek!.val; } /* 将 List 转化为 Array 并返回 */ public int[] ToArray() { if (stackPeek == null) return []; ListNode? node = stackPeek; int[] res = new int[Size()]; for (int i = res.Length - 1; i >= 0; i--) { res[i] = node!.val; node = node.next; } return res; } } ``` === "Go" ```go title="linkedlist_stack.go" /* 基于链表实现的栈 */ type linkedListStack struct { // 使用内置包 list 来实现栈 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 } /* 获取 List 用于打印 */ func (s *linkedListStack) toList() *list.List { return s.data } ``` === "Swift" ```swift title="linkedlist_stack.swift" /* 基于链表实现的栈 */ class LinkedListStack { private var _peek: ListNode? // 将头节点作为栈顶 private var _size: Int // 栈的长度 init() { _size = 0 } /* 获取栈的长度 */ func size() -> Int { _size } /* 判断栈是否为空 */ func isEmpty() -> Bool { size() == 0 } /* 入栈 */ func push(num: Int) { let node = ListNode(x: num) node.next = _peek _peek = node _size += 1 } /* 出栈 */ @discardableResult func pop() -> Int { let num = peek() _peek = _peek?.next _size -= 1 return num } /* 访问栈顶元素 */ func peek() -> Int { if isEmpty() { fatalError("栈为空") } return _peek!.val } /* 将 List 转化为 Array 并返回 */ func toArray() -> [Int] { var node = _peek var res = Array(repeating: 0, count: size()) for i in res.indices.reversed() { res[i] = node!.val node = node?.next } return res } } ``` === "JS" ```javascript title="linkedlist_stack.js" /* 基于链表实现的栈 */ class LinkedListStack { #stackPeek; // 将头节点作为栈顶 #stkSize = 0; // 栈的长度 constructor() { this.#stackPeek = null; } /* 获取栈的长度 */ get size() { return this.#stkSize; } /* 判断栈是否为空 */ isEmpty() { return this.size === 0; } /* 入栈 */ push(num) { const node = new ListNode(num); node.next = this.#stackPeek; this.#stackPeek = node; this.#stkSize++; } /* 出栈 */ pop() { const num = this.peek(); this.#stackPeek = this.#stackPeek.next; this.#stkSize--; return num; } /* 访问栈顶元素 */ peek() { if (!this.#stackPeek) throw new Error('栈为空'); return this.#stackPeek.val; } /* 将链表转化为 Array 并返回 */ toArray() { let node = this.#stackPeek; const res = new Array(this.size); for (let i = res.length - 1; i >= 0; i--) { res[i] = node.val; node = node.next; } return res; } } ``` === "TS" ```typescript title="linkedlist_stack.ts" /* 基于链表实现的栈 */ class LinkedListStack { private stackPeek: ListNode | null; // 将头节点作为栈顶 private stkSize: number = 0; // 栈的长度 constructor() { this.stackPeek = null; } /* 获取栈的长度 */ get size(): number { return this.stkSize; } /* 判断栈是否为空 */ isEmpty(): boolean { return this.size === 0; } /* 入栈 */ push(num: number): void { const node = new ListNode(num); node.next = this.stackPeek; this.stackPeek = node; this.stkSize++; } /* 出栈 */ pop(): number { const num = this.peek(); if (!this.stackPeek) throw new Error('栈为空'); this.stackPeek = this.stackPeek.next; this.stkSize--; return num; } /* 访问栈顶元素 */ peek(): number { if (!this.stackPeek) throw new Error('栈为空'); return this.stackPeek.val; } /* 将链表转化为 Array 并返回 */ toArray(): number[] { let node = this.stackPeek; const res = new Array(this.size); for (let i = res.length - 1; i >= 0; i--) { res[i] = node!.val; node = node!.next; } return res; } } ``` === "Dart" ```dart title="linkedlist_stack.dart" /* 基于链表类实现的栈 */ class LinkedListStack { ListNode? _stackPeek; // 将头节点作为栈顶 int _stkSize = 0; // 栈的长度 LinkedListStack() { _stackPeek = null; } /* 获取栈的长度 */ int size() { return _stkSize; } /* 判断栈是否为空 */ bool isEmpty() { return _stkSize == 0; } /* 入栈 */ void push(int _num) { final ListNode node = ListNode(_num); node.next = _stackPeek; _stackPeek = node; _stkSize++; } /* 出栈 */ int pop() { final int _num = peek(); _stackPeek = _stackPeek!.next; _stkSize--; return _num; } /* 访问栈顶元素 */ int peek() { if (_stackPeek == null) { throw Exception("栈为空"); } return _stackPeek!.val; } /* 将链表转化为 List 并返回 */ List toList() { ListNode? node = _stackPeek; List list = []; while (node != null) { list.add(node.val); node = node.next; } list = list.reversed.toList(); return list; } } ``` === "Rust" ```rust title="linkedlist_stack.rs" /* 基于链表实现的栈 */ #[allow(dead_code)] pub struct LinkedListStack { stack_peek: Option>>>, // 将头节点作为栈顶 stk_size: usize, // 栈的长度 } impl LinkedListStack { pub fn new() -> Self { Self { stack_peek: None, stk_size: 0, } } /* 获取栈的长度 */ pub fn size(&self) -> usize { return self.stk_size; } /* 判断栈是否为空 */ pub fn is_empty(&self) -> bool { return self.size() == 0; } /* 入栈 */ pub fn push(&mut self, num: T) { let node = ListNode::new(num); node.borrow_mut().next = self.stack_peek.take(); self.stack_peek = Some(node); self.stk_size += 1; } /* 出栈 */ pub fn pop(&mut self) -> Option { self.stack_peek.take().map(|old_head| { match old_head.borrow_mut().next.take() { Some(new_head) => { self.stack_peek = Some(new_head); } None => { self.stack_peek = None; } } self.stk_size -= 1; Rc::try_unwrap(old_head).ok().unwrap().into_inner().val }) } /* 访问栈顶元素 */ pub fn peek(&self) -> Option<&Rc>>> { self.stack_peek.as_ref() } /* 将 List 转化为 Array 并返回 */ pub fn to_array(&self, head: Option<&Rc>>>) -> Vec { if let Some(node) = head { let mut nums = self.to_array(node.borrow().next.as_ref()); nums.push(node.borrow().val); return nums; } return Vec::new(); } } ``` === "C" ```c title="linkedlist_stack.c" /* 基于链表实现的栈 */ typedef struct { ListNode *top; // 将头节点作为栈顶 int size; // 栈的长度 } LinkedListStack; /* 构造函数 */ LinkedListStack *newLinkedListStack() { LinkedListStack *s = malloc(sizeof(LinkedListStack)); s->top = NULL; s->size = 0; return s; } /* 析构函数 */ void delLinkedListStack(LinkedListStack *s) { while (s->top) { ListNode *n = s->top->next; free(s->top); s->top = n; } free(s); } /* 获取栈的长度 */ int size(LinkedListStack *s) { return s->size; } /* 判断栈是否为空 */ bool isEmpty(LinkedListStack *s) { return size(s) == 0; } /* 入栈 */ void push(LinkedListStack *s, int num) { ListNode *node = (ListNode *)malloc(sizeof(ListNode)); node->next = s->top; // 更新新加节点指针域 node->val = num; // 更新新加节点数据域 s->top = node; // 更新栈顶 s->size++; // 更新栈大小 } /* 访问栈顶元素 */ int peek(LinkedListStack *s) { if (s->size == 0) { printf("栈为空\n"); return INT_MAX; } return s->top->val; } /* 出栈 */ int pop(LinkedListStack *s) { int val = peek(s); ListNode *tmp = s->top; s->top = s->top->next; // 释放内存 free(tmp); s->size--; return val; } ``` === "Kotlin" ```kotlin title="linkedlist_stack.kt" /* 基于链表实现的栈 */ class LinkedListStack( private var stackPeek: ListNode? = null, // 将头节点作为栈顶 private var stkSize: Int = 0 // 栈的长度 ) { /* 获取栈的长度 */ fun size(): Int { return stkSize } /* 判断栈是否为空 */ fun isEmpty(): Boolean { return size() == 0 } /* 入栈 */ fun push(num: Int) { val node = ListNode(num) node.next = stackPeek stackPeek = node stkSize++ } /* 出栈 */ fun pop(): Int? { val num = peek() stackPeek = stackPeek?.next stkSize-- return num } /* 访问栈顶元素 */ fun peek(): Int? { if (isEmpty()) throw IndexOutOfBoundsException() return stackPeek?._val } /* 将 List 转化为 Array 并返回 */ fun toArray(): IntArray { var node = stackPeek val res = IntArray(size()) for (i in res.size - 1 downTo 0) { res[i] = node?._val!! node = node.next } return res } } ``` === "Ruby" ```ruby title="linkedlist_stack.rb" ### 基于链表实现的栈 ### class LinkedListStack attr_reader :size ### 构造方法 ### def initialize @size = 0 end ### 判断栈是否为空 ### def is_empty? @peek.nil? end ### 入栈 ### def push(val) node = ListNode.new(val) node.next = @peek @peek = node @size += 1 end ### 出栈 ### def pop num = peek @peek = @peek.next @size -= 1 num end ### 访问栈顶元素 ### def peek raise IndexError, '栈为空' if is_empty? @peek.val end ### 将链表转化为 Array 并反回 ### def to_array arr = [] node = @peek while node arr << node.val node = node.next end arr.reverse end end ``` === "Zig" ```zig title="linkedlist_stack.zig" // 基于链表实现的栈 fn LinkedListStack(comptime T: type) type { return struct { const Self = @This(); stack_top: ?*inc.ListNode(T) = null, // 将头节点作为栈顶 stk_size: usize = 0, // 栈的长度 mem_arena: ?std.heap.ArenaAllocator = null, mem_allocator: std.mem.Allocator = undefined, // 内存分配器 // 构造函数(分配内存+初始化栈) pub fn init(self: *Self, allocator: std.mem.Allocator) !void { if (self.mem_arena == null) { self.mem_arena = std.heap.ArenaAllocator.init(allocator); self.mem_allocator = self.mem_arena.?.allocator(); } self.stack_top = null; self.stk_size = 0; } // 析构函数(释放内存) pub fn deinit(self: *Self) void { if (self.mem_arena == null) return; self.mem_arena.?.deinit(); } // 获取栈的长度 pub fn size(self: *Self) usize { return self.stk_size; } // 判断栈是否为空 pub fn isEmpty(self: *Self) bool { return self.size() == 0; } // 访问栈顶元素 pub fn peek(self: *Self) T { if (self.size() == 0) @panic("栈为空"); return self.stack_top.?.val; } // 入栈 pub fn push(self: *Self, num: T) !void { var node = try self.mem_allocator.create(inc.ListNode(T)); node.init(num); node.next = self.stack_top; self.stack_top = node; self.stk_size += 1; } // 出栈 pub fn pop(self: *Self) T { var num = self.peek(); self.stack_top = self.stack_top.?.next; self.stk_size -= 1; return num; } // 将栈转换为数组 pub fn toArray(self: *Self) ![]T { var node = self.stack_top; var res = try self.mem_allocator.alloc(T, self.size()); @memset(res, @as(T, 0)); var i: usize = 0; while (i < res.len) : (i += 1) { res[res.len - i - 1] = node.?.val; node = node.?.next; } return res; } }; } ``` ??? pythontutor "可视化运行"
### 2.   基于数组的实现 使用数组实现栈时,我们可以将数组的尾部作为栈顶。如图 5-3 所示,入栈与出栈操作分别对应在数组尾部添加元素与删除元素,时间复杂度都为 $O(1)$ 。 === "ArrayStack" ![基于数组实现栈的入栈出栈操作](stack.assets/array_stack_step1.png){ class="animation-figure" } === "push()" ![array_stack_push](stack.assets/array_stack_step2_push.png){ class="animation-figure" } === "pop()" ![array_stack_pop](stack.assets/array_stack_step3_pop.png){ class="animation-figure" }

图 5-3   基于数组实现栈的入栈出栈操作

由于入栈的元素可能会源源不断地增加,因此我们可以使用动态数组,这样就无须自行处理数组扩容问题。以下为示例代码: === "Python" ```python title="array_stack.py" class ArrayStack: """基于数组实现的栈""" def __init__(self): """构造方法""" self._stack: list[int] = [] def size(self) -> int: """获取栈的长度""" return len(self._stack) def is_empty(self) -> bool: """判断栈是否为空""" return self.size() == 0 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 ``` === "C++" ```cpp title="array_stack.cpp" /* 基于数组实现的栈 */ class ArrayStack { private: vector stack; public: /* 获取栈的长度 */ int size() { return stack.size(); } /* 判断栈是否为空 */ bool isEmpty() { return stack.size() == 0; } /* 入栈 */ void push(int num) { stack.push_back(num); } /* 出栈 */ int pop() { int num = top(); stack.pop_back(); return num; } /* 访问栈顶元素 */ int top() { if (isEmpty()) throw out_of_range("栈为空"); return stack.back(); } /* 返回 Vector */ vector toVector() { return stack; } }; ``` === "Java" ```java title="array_stack.java" /* 基于数组实现的栈 */ class ArrayStack { private ArrayList stack; public ArrayStack() { // 初始化列表(动态数组) stack = new ArrayList<>(); } /* 获取栈的长度 */ public int size() { return stack.size(); } /* 判断栈是否为空 */ public boolean isEmpty() { return size() == 0; } /* 入栈 */ public void push(int num) { stack.add(num); } /* 出栈 */ public int pop() { if (isEmpty()) throw new IndexOutOfBoundsException(); return stack.remove(size() - 1); } /* 访问栈顶元素 */ public int peek() { if (isEmpty()) throw new IndexOutOfBoundsException(); return stack.get(size() - 1); } /* 将 List 转化为 Array 并返回 */ public Object[] toArray() { return stack.toArray(); } } ``` === "C#" ```csharp title="array_stack.cs" /* 基于数组实现的栈 */ class ArrayStack { List stack; public ArrayStack() { // 初始化列表(动态数组) stack = []; } /* 获取栈的长度 */ public int Size() { return stack.Count; } /* 判断栈是否为空 */ public bool IsEmpty() { return Size() == 0; } /* 入栈 */ public void Push(int num) { stack.Add(num); } /* 出栈 */ public int Pop() { if (IsEmpty()) throw new Exception(); var val = Peek(); stack.RemoveAt(Size() - 1); return val; } /* 访问栈顶元素 */ public int Peek() { if (IsEmpty()) throw new Exception(); return stack[Size() - 1]; } /* 将 List 转化为 Array 并返回 */ public int[] ToArray() { return [.. stack]; } } ``` === "Go" ```go title="array_stack.go" /* 基于数组实现的栈 */ type arrayStack struct { data []int // 数据 } /* 初始化栈 */ func newArrayStack() *arrayStack { return &arrayStack{ // 设置栈的长度为 0,容量为 16 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 } /* 获取 Slice 用于打印 */ func (s *arrayStack) toSlice() []int { return s.data } ``` === "Swift" ```swift title="array_stack.swift" /* 基于数组实现的栈 */ class ArrayStack { private var stack: [Int] init() { // 初始化列表(动态数组) stack = [] } /* 获取栈的长度 */ func size() -> Int { stack.count } /* 判断栈是否为空 */ func isEmpty() -> Bool { stack.isEmpty } /* 入栈 */ func push(num: Int) { stack.append(num) } /* 出栈 */ @discardableResult func pop() -> Int { if isEmpty() { fatalError("栈为空") } return stack.removeLast() } /* 访问栈顶元素 */ func peek() -> Int { if isEmpty() { fatalError("栈为空") } return stack.last! } /* 将 List 转化为 Array 并返回 */ func toArray() -> [Int] { stack } } ``` === "JS" ```javascript title="array_stack.js" /* 基于数组实现的栈 */ class ArrayStack { #stack; constructor() { this.#stack = []; } /* 获取栈的长度 */ get size() { return this.#stack.length; } /* 判断栈是否为空 */ isEmpty() { return this.#stack.length === 0; } /* 入栈 */ push(num) { this.#stack.push(num); } /* 出栈 */ pop() { if (this.isEmpty()) throw new Error('栈为空'); return this.#stack.pop(); } /* 访问栈顶元素 */ top() { if (this.isEmpty()) throw new Error('栈为空'); return this.#stack[this.#stack.length - 1]; } /* 返回 Array */ toArray() { return this.#stack; } } ``` === "TS" ```typescript title="array_stack.ts" /* 基于数组实现的栈 */ class ArrayStack { private stack: number[]; constructor() { this.stack = []; } /* 获取栈的长度 */ get size(): number { return this.stack.length; } /* 判断栈是否为空 */ isEmpty(): boolean { return this.stack.length === 0; } /* 入栈 */ push(num: number): void { this.stack.push(num); } /* 出栈 */ pop(): number | undefined { if (this.isEmpty()) throw new Error('栈为空'); return this.stack.pop(); } /* 访问栈顶元素 */ top(): number | undefined { if (this.isEmpty()) throw new Error('栈为空'); return this.stack[this.stack.length - 1]; } /* 返回 Array */ toArray() { return this.stack; } } ``` === "Dart" ```dart title="array_stack.dart" /* 基于数组实现的栈 */ class ArrayStack { late List _stack; ArrayStack() { _stack = []; } /* 获取栈的长度 */ int size() { return _stack.length; } /* 判断栈是否为空 */ bool isEmpty() { return _stack.isEmpty; } /* 入栈 */ void push(int _num) { _stack.add(_num); } /* 出栈 */ int pop() { if (isEmpty()) { throw Exception("栈为空"); } return _stack.removeLast(); } /* 访问栈顶元素 */ int peek() { if (isEmpty()) { throw Exception("栈为空"); } return _stack.last; } /* 将栈转化为 Array 并返回 */ List toArray() => _stack; } ``` === "Rust" ```rust title="array_stack.rs" /* 基于数组实现的栈 */ struct ArrayStack { stack: Vec, } impl ArrayStack { /* 初始化栈 */ fn new() -> ArrayStack { ArrayStack:: { stack: Vec::::new(), } } /* 获取栈的长度 */ fn size(&self) -> usize { self.stack.len() } /* 判断栈是否为空 */ fn is_empty(&self) -> bool { self.size() == 0 } /* 入栈 */ fn push(&mut self, num: T) { self.stack.push(num); } /* 出栈 */ fn pop(&mut self) -> Option { self.stack.pop() } /* 访问栈顶元素 */ fn peek(&self) -> Option<&T> { if self.is_empty() { panic!("栈为空") }; self.stack.last() } /* 返回 &Vec */ fn to_array(&self) -> &Vec { &self.stack } } ``` === "C" ```c title="array_stack.c" /* 基于数组实现的栈 */ typedef struct { int *data; int size; } ArrayStack; /* 构造函数 */ ArrayStack *newArrayStack() { ArrayStack *stack = malloc(sizeof(ArrayStack)); // 初始化一个大容量,避免扩容 stack->data = malloc(sizeof(int) * MAX_SIZE); stack->size = 0; return stack; } /* 析构函数 */ void delArrayStack(ArrayStack *stack) { free(stack->data); free(stack); } /* 获取栈的长度 */ int size(ArrayStack *stack) { return stack->size; } /* 判断栈是否为空 */ bool isEmpty(ArrayStack *stack) { return stack->size == 0; } /* 入栈 */ void push(ArrayStack *stack, int num) { if (stack->size == MAX_SIZE) { printf("栈已满\n"); return; } stack->data[stack->size] = num; stack->size++; } /* 访问栈顶元素 */ int peek(ArrayStack *stack) { if (stack->size == 0) { printf("栈为空\n"); return INT_MAX; } return stack->data[stack->size - 1]; } /* 出栈 */ int pop(ArrayStack *stack) { int val = peek(stack); stack->size--; return val; } ``` === "Kotlin" ```kotlin title="array_stack.kt" /* 基于数组实现的栈 */ class ArrayStack { // 初始化列表(动态数组) private val stack = mutableListOf() /* 获取栈的长度 */ fun size(): Int { return stack.size } /* 判断栈是否为空 */ fun isEmpty(): Boolean { return size() == 0 } /* 入栈 */ fun push(num: Int) { stack.add(num) } /* 出栈 */ fun pop(): Int { if (isEmpty()) throw IndexOutOfBoundsException() return stack.removeAt(size() - 1) } /* 访问栈顶元素 */ fun peek(): Int { if (isEmpty()) throw IndexOutOfBoundsException() return stack[size() - 1] } /* 将 List 转化为 Array 并返回 */ fun toArray(): Array { return stack.toTypedArray() } } ``` === "Ruby" ```ruby title="array_stack.rb" ### 基于数组实现的栈 ### class ArrayStack ### 构造方法 ### def initialize @stack = [] end ### 获取栈的长度 ### def size @stack.length end ### 判断栈是否为空 ### def is_empty? @stack.empty? end ### 入栈 ### def push(item) @stack << item end ### 出栈 ### def pop raise IndexError, '栈为空' if is_empty? @stack.pop end ### 访问栈顶元素 ### def peek raise IndexError, '栈为空' if is_empty? @stack.last end ### 返回列表用于打印 ### def to_array @stack end end ``` === "Zig" ```zig title="array_stack.zig" // 基于数组实现的栈 fn ArrayStack(comptime T: type) type { return struct { const Self = @This(); stack: ?std.ArrayList(T) = null, // 构造方法(分配内存+初始化栈) pub fn init(self: *Self, allocator: std.mem.Allocator) void { if (self.stack == null) { self.stack = std.ArrayList(T).init(allocator); } } // 析构方法(释放内存) pub fn deinit(self: *Self) void { if (self.stack == null) return; self.stack.?.deinit(); } // 获取栈的长度 pub fn size(self: *Self) usize { return self.stack.?.items.len; } // 判断栈是否为空 pub fn isEmpty(self: *Self) bool { return self.size() == 0; } // 访问栈顶元素 pub fn peek(self: *Self) T { if (self.isEmpty()) @panic("栈为空"); return self.stack.?.items[self.size() - 1]; } // 入栈 pub fn push(self: *Self, num: T) !void { try self.stack.?.append(num); } // 出栈 pub fn pop(self: *Self) T { var num = self.stack.?.pop(); return num; } // 返回 ArrayList pub fn toList(self: *Self) std.ArrayList(T) { return self.stack.?; } }; } ``` ??? pythontutor "可视化运行"
## 5.1.3   两种实现对比 **支持操作** 两种实现都支持栈定义中的各项操作。数组实现额外支持随机访问,但这已超出了栈的定义范畴,因此一般不会用到。 **时间效率** 在基于数组的实现中,入栈和出栈操作都在预先分配好的连续内存中进行,具有很好的缓存本地性,因此效率较高。然而,如果入栈时超出数组容量,会触发扩容机制,导致该次入栈操作的时间复杂度变为 $O(n)$ 。 在基于链表的实现中,链表的扩容非常灵活,不存在上述数组扩容时效率降低的问题。但是,入栈操作需要初始化节点对象并修改指针,因此效率相对较低。不过,如果入栈元素本身就是节点对象,那么可以省去初始化步骤,从而提高效率。 综上所述,当入栈与出栈操作的元素是基本数据类型时,例如 `int` 或 `double` ,我们可以得出以下结论。 - 基于数组实现的栈在触发扩容时效率会降低,但由于扩容是低频操作,因此平均效率更高。 - 基于链表实现的栈可以提供更加稳定的效率表现。 **空间效率** 在初始化列表时,系统会为列表分配“初始容量”,该容量可能超出实际需求;并且,扩容机制通常是按照特定倍率(例如 2 倍)进行扩容的,扩容后的容量也可能超出实际需求。因此,**基于数组实现的栈可能造成一定的空间浪费**。 然而,由于链表节点需要额外存储指针,**因此链表节点占用的空间相对较大**。 综上,我们不能简单地确定哪种实现更加节省内存,需要针对具体情况进行分析。 ## 5.1.4   栈的典型应用 - **浏览器中的后退与前进、软件中的撤销与反撤销**。每当我们打开新的网页,浏览器就会对上一个网页执行入栈,这样我们就可以通过后退操作回到上一个网页。后退操作实际上是在执行出栈。如果要同时支持后退和前进,那么需要两个栈来配合实现。 - **程序内存管理**。每次调用函数时,系统都会在栈顶添加一个栈帧,用于记录函数的上下文信息。在递归函数中,向下递推阶段会不断执行入栈操作,而向上回溯阶段则会不断执行出栈操作。