文章

数据结构复习笔记 - 链式栈

数据结构复习笔记 - 链式栈

数据结构复习笔记 - 链式栈

简单介绍

链式栈使用单向链表实现,_topNode 指向栈顶节点。链表从头节点向下生长,入栈操作在链表头部插入节点,出栈操作删除头节点。时间复杂度均为 O(1),空间可动态扩展。

方法列表

方法功能返回值
push(T entity)入栈void
pop()出栈bool
top()获取栈顶元素T
isEmpty()判空bool
clear()清空栈void

重点注意

  • 必须实现三大安全函数:析构函数、拷贝构造函数、赋值运算符重载
  • pop()必须先保存 next 指针再 delete,否则会导致 use-after-free
  • 拷贝构造和赋值运算符需要用 const 引用参数,避免无限递归
  • 深拷贝时需要借助临时栈反转顺序,保证拷贝后栈顺序一致

完整代码

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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
 * 链表节点结构体
 * @tparam T 数据域类型
 */
template <class T> struct Node {
  T data;           // 数据域,存储节点数据
  Node *next;       // 指针域,指向下一个节点

  // 构造函数,统一初始化数据域和指针域
  Node(T d) : data(d), next(nullptr) {}
};

/**
 * 链式栈模板类
 * 使用单向链表实现,_topNode 指向栈顶节点
 * @tparam T 元素类型
 */
template <class T> class LinkedStack {
private:
  Node<T> *_topNode;  // 栈顶指针,nullptr 表示空栈

  /**
   * 深拷贝辅助函数
   * 通过临时栈反转顺序,确保拷贝后栈顺序与原栈一致
   * @param original 要拷贝的源栈
   */
  void copyFrom(const LinkedStack<T> &original) {
    // 临时栈:中转元素,保证拷贝后顺序和原栈一致
    LinkedStack<T> tempStack;

    // 遍历原栈,压入临时栈(原栈栈顶 → 临时栈栈顶)
    Node<T> *curr = original._topNode;
    while (curr != nullptr) {
      tempStack.push(curr->data);
      curr = curr->next;
    }

    // 把临时栈弹出,压入当前栈(恢复正确顺序)
    while (!tempStack.isEmpty()) {
      push(tempStack.top());
      tempStack.pop();
    }
  }

public:
  /**
   * 默认构造函数
   * 初始化栈顶指针为 nullptr
   */
  LinkedStack() : _topNode(nullptr) {}

  /**
   * 析构函数
   * 清空栈,释放所有节点内存
   */
  ~LinkedStack() { clear(); }

  /**
   * 拷贝构造函数
   * 实现深拷贝,确保新栈与原栈数据独立
   * @param original 要拷贝的源栈
   */
  LinkedStack(const LinkedStack<T> &original) : _topNode(nullptr) {
    copyFrom(original);
  }

  /**
   * 赋值运算符重载
   * 实现深拷贝,处理自赋值情况
   * @param other 要拷贝的源栈
   * @return 引用,便于链式赋值
   */
  LinkedStack<T> &operator=(const LinkedStack<T> &other) {
    if (this == &other) {
      return *this;
    }
    clear();
    copyFrom(other);
    return *this;
  }

  /**
   * 出栈操作
   * 先保存 next 指针,再删除节点,避免 use-after-free
   * @return 成功返回 true,空栈返回 false
   */
  bool pop() {
    if (!isEmpty()) {
      Node<T> *old = _topNode;        // 1. 保存当前栈顶节点
      _topNode = _topNode->next;      // 2. 栈顶下移
      delete old;                     // 3. 释放原栈顶节点内存
      return true;
    }
    return false;
  }

  /**
   * 入栈操作
   * 在链表头部插入新节点,新节点成为栈顶
   * @param entity 要入栈的元素
   */
  void push(T entity) {
    if (_topNode == nullptr) {
      // 空栈情况:直接创建新节点作为栈顶
      _topNode = new Node(entity);
      return;
    }

    // 非空栈情况:
    // 1. 创建新节点
    Node<T> *toPush = new Node(entity);
    // 2. 新节点指向原栈顶
    toPush->next = _topNode;
    // 3. 更新栈顶指针
    _topNode = toPush;
  }

  /**
   * 判空操作
   * @return 栈为空返回 true,否则返回 false
   */
  bool isEmpty() { return _topNode == nullptr; }

  /**
   * 获取栈顶元素
   * @return 栈顶元素,空栈返回 T() 默认构造
   */
  T top() {
    if (isEmpty()) {
      return T();
    } else {
      return _topNode->data;
    }
  }

  /**
   * 清空栈操作
   * 循环调用 pop() 释放所有节点
   */
  void clear() {
    while (_topNode) {
      pop();
    }
  }
};
本文由作者按照 CC BY 4.0 进行授权