栈(stack)是一种先进后出的线性数据结构。

image-20260617105631480

栈的常用操作

// 初始化栈

stack<int> stack;

// 入栈
stack.push(1);

// 访问栈顶元素
int top = stack.top();

// 出栈
stack.pop();

// 获取栈的大小
int size = stack.size();

// 判空
bool empty = stack.empty();

栈的实现

栈可以视为一种受限的数组或链表,因为只能在栈顶进行插入或者删除。

基于链表的实现

image-20260617110214148

image-20260617110244568

利用“头插法”,入栈操作只需要将元素插入链表头部,出栈操作只需要从链表中删除头节点。

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("stack is empty");
       }
       
       return stackTop->val;
     }
  
  vector<int> toVector() {
    ListNode* node = stackTop;
    vector<int> res(size());
    
    for (int i = res.size() - 1; i >= 0; --i) {
      res[i] = node->val;
      node = node->next;
    }
    
    return res;
  }
}

基于数组的实现

image-20260617111401905

由于栈的元素可能源源不断增加,因此使用动态数组实现比较合理。

class ArrayStack {
 private:
   vector<int> stack;
 public:
  int size() {
    return stack.size();
  }
  
  bool isEmpty() {
    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("stack is empty");
    return stack.back();
  }
  
  vector<int> toVector() {
    return stack;
  }
}

两种实现对比

  • 基于数组实现的栈在触发扩容机制时,时间效率会降低,额外申请但尚未使用的空间也会造成浪费;但由于扩容是低频操作,因此平均效率更高。
  • 基于链表实现的栈,单个节点占用的空间相对大。

栈的典型应用

  • 浏览器的后退与前进、撤销与恢复。
  • 程序运行内存管理,函数调用时会添加栈帧记录函数上下文信息。