栈链与栈的区别
1. 基本概念
-
栈(Stack):
是一种抽象数据类型(ADT),遵循后进先出(LIFO)原则,核心操作包括push
(压栈)、pop
(弹栈)、peek
(查看栈顶)。 -
链式栈(Linked Stack,或“栈链”):
是栈的具体实现方式,使用链表(动态节点链接)存储数据,通过指针管理栈顶元素。2. 核心区别
对比项 栈(抽象概念) 链式栈(具体实现) 存储结构 可以是数组或链表 必须基于链表 容量限制 数组实现有固定大小;链表实现无固定限制 动态分配内存,无固定容量限制 内存占用 数组实现可能浪费空间 按需分配内存,空间利用率高 操作时间复杂度 push
/pop
均为 O(1)(数组或链表)push
/pop
均为 O(1)(仅链表头操作)适用场景 需要快速随机访问时用数组;否则用链表 适合频繁动态扩容的场景
3. 链式栈的优势
-
动态扩容:无需预先分配固定内存,避免栈溢出。
-
内存高效:按需分配节点,节省未使用空间。
-
实现灵活:插入/删除仅需调整指针,适合高频操作。
程序功能分析
该程序实现了一个链式栈(Linked Stack),支持以下操作:
-
压栈(push):将元素添加到栈顶。
-
弹栈(pop):移除并返回栈顶元素。
-
判空(isempty):检查栈是否为空。
-
查看栈顶(peek):返回栈顶元素的值(不删除)。
-
打印所有元素(printstack):按栈顶到栈底的顺序输出元素。
程序结构分析
-
头文件(LinkStack.h):
-
定义模板类
linkstack<T>
,支持泛型数据类型。 -
节点结构体
Node
:-
包含数据成员
m_data
和指向下一节点的指针m_next
。 -
构造函数直接初始化数据与指针。
-
-
栈核心逻辑:
-
栈顶指针
topNode
初始化为nullptr
。 -
通过动态分配节点实现链式存储。
-
-
-
源文件(LinkStack.cpp):
-
主函数测试链栈功能:
-
压入
16
、77
、89
。 -
检查栈是否为空(输出“有值”)。
-
打印栈内所有元素(预期输出:
89 -> 77 -> 16 -> null
)。
-
-
函数实现思路
-
初始化栈:
struct Node { T m_data;//节点数据 Node* m_next;//next指针,指向下一个节点 Node(T data,Node *next):m_data(data),m_next(next) {};//结构体的构造函数(数据,尾指针指向下一个节点) }; Node* topNode;//栈顶指针
定义一个结构体实现栈的定义,链式栈是以节点为单位,每个节点包含data值和next指针指向下一个节点,因为是栈结构,遵循后进先出的原则,栈顶指针指向头节点。
-
压栈(push)
-
创建新节点,新节点的
m_next
指向当前栈顶topNode
。 -
更新
topNode
为新节点,时间复杂度为 O(1)。void push(const T &val) { Node *newnode= new Node(val,topNode);//创建一个新节点,栈顶节点原来指向的是新节点的next的位置,所以创建的时候把topnode的位置转给新节点的next来指向 topNode = newnode;//将原来的栈顶指针指向新的节点 }
-
-
弹栈(pop)
-
若栈非空,保存栈顶数据,将
topNode
指向下一节点,删除原栈顶节点。 -
若栈空,返回
0
(可能不适用于非整型数据),时间复杂度为 O(1)。T pop() { if (isempty()) { cout << "栈已空" << endl; return 0; } //创建一个临时指针指向要pop的节点 Node* temp = topNode; //把节点内的数据取出来保存 T val = temp->m_data; //把栈顶指针挪到下一个位置,原来的准备删除 topNode = topNode->m_next; //删除原来的栈顶节点 delete temp; return val;//返回保存的数据 }
-
-
判空(isempty)
-
直接检查
topNode
是否为nullptr
,时间复杂度 O(1)。bool isempty() { if (topNode == nullptr) { return true; } else { return false; } }
-
-
查看栈顶(peek)
-
若栈非空,返回
topNode->m_data
。 -
问题:栈空的情况下按照正常情况需要抛出异常,但我懒得弄,就用了return 0取代,这里注意一下。
//返回栈顶元素的值 T peek() { if (isempty()) { cout << "栈已空" << endl; return; } return topNode->m_data; }
-
-
打印元素(printstack)
-
遍历栈顶到栈底,用
->
连接元素,时间复杂度 O(n)。//遍历所有栈内元素 void printstack() { Node* ptr = topNode; cout << "所有的栈元素:"; while (ptr != nullptr) { cout << ptr->m_data; if (ptr->m_next != nullptr) { cout << " -> "; } ptr = ptr->m_next; } cout << " ->null " << endl; }
-
总结
-
栈是逻辑模型:定义操作规则(LIFO),与具体实现无关。
-
链式栈是物理实现:用链表动态管理数据,解决固定容量问题。
-
核心选择依据:根据场景需求选择数组栈(快速访问)或链式栈(动态灵活)。