【数据结构】链栈的基本操作
目录
一、链栈基础结构
二、核心操作算法详解
1. 初始化栈(InitStack)
2. 判断栈是否为空(StackEmpty)
3. 求栈的长度(StackLength)
4. 进栈操作(Push)
5. 出栈操作(Pop)
6. 取栈顶元素(GetTop)
7. 清空栈(ClearStack)
8. 销毁栈(DestroyStack)
9. 遍历栈(TraverseStack)
10. 复制栈(CopyStack)
11. 判断两个栈是否相等(StackEqual)
12. 逆置栈(ReverseStack)
三、链栈的基本操作的完整代码展示
(一)C++代码
(二)Python代码
(三)Java代码
四、程序运行结果展示
(一)C++程序运行截图
(二)Python程序运行截图
(三)Java程序运行截图
五、总结
一、链栈基础结构
链栈是用链表实现的栈(先进后出,LIFO),核心结构是StackNode
节点和LinkStack
栈顶指针:
typedef struct StackNode {SElemType data; // 数据域:存储栈元素struct StackNode *next; // 指针域:指向后一个节点(栈底方向)
} StackNode, *LinkStack; // LinkStack本质是指向StackNode的指针(栈顶指针)
- 栈顶指针
S
指向栈中最顶部的节点(最后入栈的元素) - 空栈时,
S = NULL
(无任何节点) - 元素入栈 / 出栈仅在栈顶操作(链表头部),符合栈 "先进后出" 特性
二、核心操作算法详解
1. 初始化栈(InitStack)
功能:创建一个空栈算法步骤:
- 将栈顶指针
S
直接置为NULL
- 此时栈中无任何节点,即为空栈
代码解析:
void InitStack(LinkStack &S) {S = NULL; // 栈顶指针置空,代表空栈
}
复杂度:
- 时间复杂度:O (1)(仅需一次指针赋值)
- 空间复杂度:O (1)(无额外空间占用)注意:初始化后必须调用此函数,否则栈顶指针可能为随机值,导致后续操作出错。
2. 判断栈是否为空(StackEmpty)
功能:检查栈中是否有元素算法步骤:
- 检查栈顶指针
S
是否为NULL
- 若
S == NULL
,返回true
(空栈);否则返回false
(非空栈)
代码解析:
bool StackEmpty(LinkStack S) {return (S == NULL); // 栈顶指针为空 → 空栈
}
复杂度:
- 时间复杂度:O (1)(仅需一次指针比较)
- 空间复杂度:O (1)注意:几乎所有栈操作前都需要先判断栈是否为空(如出栈、取栈顶),避免对空栈操作导致错误。
3. 求栈的长度(StackLength)
功能:计算栈中元素的个数算法步骤:
- 初始化计数器
length = 0
,创建临时指针p
并指向栈顶S
- 循环遍历链表:当
p != NULL
时,计数器length++
,p
移动到下一个节点(p = p->next
) - 遍历结束后,
length
即为栈的长度
代码解析:
int StackLength(LinkStack S) {int length = 0;LinkStack p = S; // 临时指针,从栈顶开始遍历while (p != NULL) {length++; // 计数当前节点p = p->next; // 移动到下一个节点(栈底方向)}return length;
}
复杂度:
- 时间复杂度:O (n)(n 为栈长度,需遍历所有节点)
- 空间复杂度:O (1)(仅用一个临时指针)注意:链栈无法像顺序栈那样直接通过数组下标获取长度,必须遍历链表。
4. 进栈操作(Push)
功能:将元素e
插入栈顶(成为新的栈顶元素)算法步骤:
- 创建新节点
p
(new StackNode
) - 新节点数据域赋值:
p->data = e
- 新节点指针域指向原栈顶:
p->next = S
(原栈顶成为新节点的下一个节点) - 更新栈顶指针:
S = p
(新节点成为新的栈顶)
代码解析:
void Push(LinkStack &S, SElemType e) {LinkStack p = new StackNode; // 1. 创建新节点p->data = e; // 2. 存入数据p->next = S; // 3. 新节点指向原栈顶S = p; // 4. 更新栈顶为新节点
}
示意图:
原栈:S → A → B → NULL(栈顶为A)
进栈e后:
S → e → A → B → NULL(栈顶为e)
复杂度:
- 时间复杂度:O (1)(仅需 4 步指针操作,无需遍历)
- 空间复杂度:O (1)(仅创建一个新节点)注意:进栈是链栈的核心操作,利用链表头部插入的特性实现,效率极高。
5. 出栈操作(Pop)
功能:移除栈顶元素,并返回该元素的值算法步骤:
- 先判断栈是否为空(
StackEmpty(S)
):若为空,输出错误信息,返回特殊值(如 - 1) - 若栈非空,创建临时指针
p
指向栈顶S
(暂存栈顶节点) - 取出栈顶元素值:
e = p->data
- 更新栈顶指针:
S = S->next
(原栈顶的下一个节点成为新栈顶) - 释放原栈顶节点的内存(
delete p
),避免内存泄漏 - 返回取出的元素值
e
代码解析:
SElemType Pop(LinkStack &S) {if (StackEmpty(S)) { // 1. 检查空栈cerr << "错误:栈为空,无法执行出栈操作!" << endl;return -1;}LinkStack p = S; // 2. 暂存栈顶节点SElemType e = p->data;// 3. 取出栈顶元素S = S->next; // 4. 更新栈顶指针delete p; // 5. 释放内存return e; // 6. 返回元素
}
示意图:
原栈:S → e → A → B → NULL(栈顶为e)
出栈后:
S → A → B → NULL(栈顶为A,e被移除并返回)
复杂度:
- 时间复杂度:O (1)(仅需几步指针操作)
- 空间复杂度:O (1)(仅用一个临时指针)注意:出栈必须释放原栈顶节点的内存,否则会导致内存泄漏;空栈时必须报错,避免访问空指针。
6. 取栈顶元素(GetTop)
功能:获取栈顶元素的值(不改变栈结构,元素仍在栈中)算法步骤:
- 判断栈是否为空:若为空,输出错误信息,返回特殊值
- 若栈非空,直接返回栈顶节点的数据(
S->data
)
代码解析:
SElemType GetTop(LinkStack S) {if (StackEmpty(S)) { // 检查空栈cerr << "错误:栈为空,无栈顶元素!" << endl;return -1;}return S->data; // 返回栈顶元素值
}
复杂度:
- 时间复杂度:O (1)(直接访问栈顶节点)
- 空间复杂度:O (1)与出栈的区别:取栈顶仅读取元素,不改变栈结构;出栈会移除元素并修改栈结构。
7. 清空栈(ClearStack)
功能:删除栈中所有元素,但保留栈的结构(最终为一个空栈)算法步骤:
- 创建两个临时指针
p
和q
,p
初始指向栈顶S
- 循环遍历所有节点:
q = p
(暂存当前节点)p = p->next
(p
移动到下一个节点)delete q
(释放当前节点内存)
- 遍历结束后,将栈顶指针
S
置为NULL
(此时栈为空)
代码解析:
void ClearStack(LinkStack &S) {LinkStack p, q;p = S;while (p != NULL) {q = p; // 暂存当前节点p = p->next; // 移动到下一个节点delete q; // 释放当前节点}S = NULL; // 栈顶指针置空,成为空栈
}
复杂度:
- 时间复杂度:O (n)(需遍历并释放所有节点)
- 空间复杂度:O (1)(仅用两个临时指针)与销毁栈的区别:清空栈后,栈仍可继续使用(可重新进栈);销毁栈的逻辑与清空栈一致(链栈无额外结构),但语义上代表栈生命周期结束。
8. 销毁栈(DestroyStack)
功能:释放栈占用的所有内存,结束栈的生命周期算法步骤:
- 直接调用
ClearStack(S)
(释放所有节点内存,并将S
置为NULL
) - 链栈无额外的容器结构(如顺序栈的数组),因此无需其他操作
代码解析:
void DestroyStack(LinkStack &S) {ClearStack(S); // 释放所有节点,栈顶指针置空
}
复杂度:
- 时间复杂度:O (n)(同 ClearStack)
- 空间复杂度:O (1)注意:销毁后若需使用栈,必须重新调用
InitStack
初始化。
9. 遍历栈(TraverseStack)
功能:从栈顶到栈底依次打印所有元素算法步骤:
- 判断栈是否为空:若为空,输出提示信息
- 若栈非空,创建临时指针
p
指向栈顶S
- 循环遍历:当
p != NULL
时,打印p->data
,p
移动到下一个节点(p = p->next
) - 遍历结束后换行
代码解析:
void TraverseStack(LinkStack S) {if (StackEmpty(S)) {cout << "栈为空,无元素可遍历!" << endl;return;}cout << "链栈元素(从栈顶到栈底):";LinkStack p = S;while (p != NULL) {cout << p->data << " "; // 打印当前元素p = p->next; // 移动到下一个节点(栈底方向)}cout << endl;
}
示例:栈中元素(从栈顶到栈底)为50,40,30,20,10
,遍历后输出:链栈元素(从栈顶到栈底):50 40 30 20 10
复杂度:
- 时间复杂度:O (n)(需遍历所有节点)
- 空间复杂度:O (1)
10. 复制栈(CopyStack)
功能:将栈S
的所有元素复制到栈T
,复制后T
与S
的元素顺序完全一致(栈顶到栈底元素相同)算法步骤:
- 若目标栈
T
非空,先调用ClearStack(T)
清空T
(避免内存泄漏) - 若源栈
S
为空,将T
置为NULL
,返回true
- 若
S
非空,创建辅助栈temp
并初始化 - 遍历源栈
S
,将所有元素依次压入辅助栈temp
(此时temp
的元素是S
的逆序,因为栈是先进后出) - 遍历辅助栈
temp
,将所有元素依次弹出并压入目标栈T
(此时T
的元素顺序与S
完全一致) - 返回
true
代码解析:
bool CopyStack(LinkStack S, LinkStack &T) {if (T != NULL) {ClearStack(T); // 1. 先清空目标栈}if (StackEmpty(S)) { // 2. 源栈为空,目标栈也为空T = NULL;return true;}LinkStack temp;InitStack(temp); // 3. 创建辅助栈LinkStack p = S;// 4. 将S的元素逆序存入tempwhile (p != NULL) {Push(temp, p->data);p = p->next;}// 5. 将temp的元素弹出并存入T,恢复原顺序while (!StackEmpty(temp)) {Push(T, Pop(temp));}return true;
}
示意图:
源栈S:顶→50→40→30→底
辅助栈temp:先存入50→40→30 → temp中顺序为顶→30→40→50→底
目标栈T:从temp弹出30→40→50并压入 → T中顺序为顶→50→40→30→底(与S一致)
复杂度:
- 时间复杂度:O (n)(遍历
S
和temp
各一次,共 2n 步) - 空间复杂度:O (n)(辅助栈
temp
需存储 n 个元素)关键逻辑:利用辅助栈反转顺序,确保复制后的栈与原栈元素顺序一致(若直接复制链表,T
的元素会是S
的逆序,不符合栈的特性)。
11. 判断两个栈是否相等(StackEqual)
功能:检查两个栈S
和T
是否完全相等(元素数量相同,且对应位置元素的值相同)算法步骤:
- 调用
StackLength
分别获取S
和T
的长度,若长度不同,直接返回false
- 若长度相同,创建两个临时指针
p
(指向S
顶)和q
(指向T
顶) - 循环遍历两个栈:
- 若
p->data != q->data
,返回false
p
和q
分别移动到下一个节点(p = p->next
,q = q->next
)
- 若
- 遍历结束后,返回
true
代码解析:
bool StackEqual(LinkStack S, LinkStack T) {// 1. 长度不同则不相等if (StackLength(S) != StackLength(T)) {return false;}LinkStack p = S, q = T;// 2. 逐个比较元素while (p != NULL && q != NULL) {if (p->data != q->data) {return false;}p = p->next;q = q->next;}return true;
}
复杂度:
- 时间复杂度:O (n)(求长度需 O (n),比较元素需 O (n),总 O (n))
- 空间复杂度:O (1)(仅用两个临时指针)
12. 逆置栈(ReverseStack)
功能:反转栈中元素的顺序(原栈顶元素变为栈底,原栈底元素变为栈顶)算法步骤:
- 若栈为空(
StackEmpty(S)
)或只有 1 个元素(StackLength(S) == 1
),无需逆置,直接返回 - 若栈有多个元素,创建三个指针:
prev = NULL
(前一个节点)、curr = S
(当前节点)、next = NULL
(下一个节点) - 循环反转指针方向:
next = curr->next
(保存当前节点的下一个节点)curr->next = prev
(当前节点的指针改为指向前一个节点)prev = curr
(prev
移动到当前节点)curr = next
(curr
移动到下一个节点)
- 循环结束后,
prev
指向原栈底节点(新栈顶),更新栈顶指针S = prev
代码解析:
void ReverseStack(LinkStack &S) {// 1. 空栈或单元素栈无需逆置if (StackEmpty(S) || StackLength(S) == 1) {return;}LinkStack prev = NULL;LinkStack curr = S;LinkStack next = NULL;// 2. 反转链表指针方向while (curr != NULL) {next = curr->next; // 保存下一个节点curr->next = prev; // 反转当前节点指针prev = curr; // 移动prevcurr = next; // 移动curr}S = prev; // 3. 更新栈顶为原栈底
}
示意图:
原栈:S→50→40→30→20→10→NULL(顶→50,底→10)
反转指针后:
10→20→30→40→50→NULL,S指向10
逆置后栈:S→10→20→30→40→50→NULL(顶→10,底→50)
复杂度:
- 时间复杂度:O (n)(需遍历所有节点一次)
- 空间复杂度:O (1)(仅用三个临时指针,原地反转)优势:相比 "用辅助栈逆置"(空间 O (n)),此算法通过反转链表指针实现原地逆置,空间效率更高。
三、链栈的基本操作的完整代码展示
(一)C++代码
#include <iostream>
#include <windows.h> // 引入Windows系统头文件
using namespace std;// 定义栈元素类型
typedef int SElemType;// 链栈节点结构定义
typedef struct StackNode {SElemType data; // 数据域struct StackNode *next; // 指针域,指向后继节点
} StackNode, *LinkStack;// 函数声明
void InitStack(LinkStack &S); // 链栈的初始化
bool StackEmpty(LinkStack S); // 判断链栈是否为空
int StackLength(LinkStack S); // 求链栈的长度
void Push(LinkStack &S, SElemType e); // 链栈进栈操作
SElemType Pop(LinkStack &S); // 链栈出栈操作
SElemType GetTop(LinkStack S); // 取链栈栈顶元素
void ClearStack(LinkStack &S); // 清空链栈(保留栈结构)
void DestroyStack(LinkStack &S); // 销毁链栈(释放所有资源)
void TraverseStack(LinkStack S); // 遍历链栈元素(从栈顶到栈底)
bool CopyStack(LinkStack S, LinkStack &T); // 复制栈(将S复制到T)
bool StackEqual(LinkStack S, LinkStack T); // 判断两个栈是否相等
void ReverseStack(LinkStack &S); // 逆置链栈// 测试函数
int main() {SetConsoleOutputCP(CP_UTF8); // 强制控制台使用UTF-8解析输出LinkStack S, T;// 初始化栈InitStack(S);InitStack(T);cout << "初始化链栈S后,栈是否为空:" << (StackEmpty(S) ? "是" : "否") << endl;// 进栈操作cout << "\n执行进栈操作:依次入栈 10, 20, 30, 40, 50" << endl;Push(S, 10);Push(S, 20);Push(S, 30);Push(S, 40);Push(S, 50);TraverseStack(S);cout << "栈S的长度:" << StackLength(S) << endl;// 复制栈操作cout << "\n复制栈S到栈T..." << endl;CopyStack(S, T);cout << "栈T的元素:";TraverseStack(T);cout << "栈S和栈T是否相等:" << (StackEqual(S, T) ? "是" : "否") << endl;// 逆置栈操作cout << "\n逆置栈S..." << endl;ReverseStack(S);cout << "逆置后栈S的元素:";TraverseStack(S);cout << "栈S和栈T是否相等:" << (StackEqual(S, T) ? "是" : "否") << endl;// 再次逆置恢复原顺序ReverseStack(S);cout << "再次逆置后栈S的元素:";TraverseStack(S);// 出栈和取栈顶操作cout << "\n执行出栈操作:" << endl;cout << "出栈元素:" << Pop(S) << endl;cout << "出栈元素:" << Pop(S) << endl;TraverseStack(S);cout << "当前栈顶元素:" << GetTop(S) << endl;cout << "当前栈S的长度:" << StackLength(S) << endl;// 清空栈操作cout << "\n清空栈S..." << endl;ClearStack(S);cout << "清空后栈S是否为空:" << (StackEmpty(S) ? "是" : "否") << endl;cout << "清空后栈S的长度:" << StackLength(S) << endl;// 测试栈Tcout << "\n栈T的元素:";TraverseStack(T);cout << "栈T的长度:" << StackLength(T) << endl;// 销毁栈cout << "\n销毁链栈..." << endl;DestroyStack(S);DestroyStack(T);cout << "销毁后,栈S是否为空:" << (StackEmpty(S) ? "是" : "否") << endl;cout << "销毁后,栈T是否为空:" << (StackEmpty(T) ? "是" : "否") << endl;return 0;
}// 链栈的初始化
void InitStack(LinkStack &S) {S = NULL; // 栈顶指针置空,表示空栈
}// 判断链栈是否为空
bool StackEmpty(LinkStack S) {return (S == NULL); // 栈顶指针为空则栈空
}// 求链栈的长度
int StackLength(LinkStack S) {int length = 0;LinkStack p = S;while (p != NULL) {length++;p = p->next;}return length;
}// 链栈进栈操作
void Push(LinkStack &S, SElemType e) {LinkStack p = new StackNode; // 创建新节点p->data = e; // 存入数据p->next = S; // 新节点指向原栈顶S = p; // 更新栈顶指针为新节点
}// 链栈出栈操作
SElemType Pop(LinkStack &S) {if (StackEmpty(S)) {cerr << "错误:栈为空,无法执行出栈操作!" << endl;return -1; // 栈空时返回特殊值}LinkStack p = S; // 暂存栈顶节点SElemType e = p->data; // 获取栈顶元素值S = S->next; // 更新栈顶指针delete p; // 释放原栈顶节点内存return e; // 返回出栈元素
}// 取链栈栈顶元素
SElemType GetTop(LinkStack S) {if (StackEmpty(S)) {cerr << "错误:栈为空,无栈顶元素!" << endl;return -1; // 栈空时返回特殊值}return S->data; // 返回栈顶元素值
}// 清空链栈(保留栈结构,仅清空元素)
void ClearStack(LinkStack &S) {LinkStack p, q;p = S;while (p != NULL) {q = p;p = p->next;delete q;}S = NULL; // 栈顶指针置空
}// 销毁链栈(释放所有资源)
void DestroyStack(LinkStack &S) {ClearStack(S); // 清空栈元素// 链栈无需额外销毁操作,因为栈本身是指针
}// 遍历链栈元素(从栈顶到栈底)
void TraverseStack(LinkStack S) {if (StackEmpty(S)) {cout << "栈为空,无元素可遍历!" << endl;return;}cout << "链栈元素(从栈顶到栈底):";LinkStack p = S;while (p != NULL) {cout << p->data << " ";p = p->next;}cout << endl;
}// 复制栈(将S复制到T)
bool CopyStack(LinkStack S, LinkStack &T) {if (T != NULL) {ClearStack(T); // 先清空目标栈}if (StackEmpty(S)) {T = NULL;return true;}// 辅助栈用于临时存储元素(解决顺序问题)LinkStack temp;InitStack(temp);LinkStack p = S;// 先将S的元素逆序存入临时栈while (p != NULL) {Push(temp, p->data);p = p->next;}// 再将临时栈的元素存入T,恢复原顺序while (!StackEmpty(temp)) {Push(T, Pop(temp));}return true;
}// 判断两个栈是否相等(元素数量和对应位置元素都相同)
bool StackEqual(LinkStack S, LinkStack T) {// 长度不同则直接不相等if (StackLength(S) != StackLength(T)) {return false;}LinkStack p = S, q = T;while (p != NULL && q != NULL) {if (p->data != q->data) {return false;}p = p->next;q = q->next;}return true;
}// 逆置链栈(改变元素顺序)
void ReverseStack(LinkStack &S) {if (StackEmpty(S) || StackLength(S) == 1) {return; // 空栈或只有一个元素无需逆置}LinkStack prev = NULL;LinkStack curr = S;LinkStack next = NULL;// 反转链表指针方向while (curr != NULL) {next = curr->next; // 保存下一个节点curr->next = prev; // 反转当前节点指针prev = curr; // 移动prev到当前节点curr = next; // 移动curr到下一个节点}S = prev; // 更新栈顶指针
}
(二)Python代码
# 定义栈节点类
class StackNode:def __init__(self, data):self.data = data # 数据域self.next = None # 指针域,指向后继节点# 链栈初始化:返回空栈(None表示空栈)
def init_stack():return None# 判断链栈是否为空
def stack_empty(s):return s is None# 求链栈的长度
def stack_length(s):length = 0p = swhile p is not None:length += 1p = p.nextreturn length# 链栈进栈操作
def push(s, e):# 创建新节点p = StackNode(e)# 新节点指向原栈顶p.next = s# 更新栈顶指针为新节点return p# 链栈出栈操作
def pop(s):if stack_empty(s):print("错误:栈为空,无法执行出栈操作!", file=sys.stderr)return None, s # 返回None表示出错,栈顶不变# 暂存栈顶节点p = s# 获取栈顶元素值e = p.data# 更新栈顶指针s = s.next# Python会自动回收内存,无需手动释放return e, s# 取链栈栈顶元素
def get_top(s):if stack_empty(s):print("错误:栈为空,无栈顶元素!", file=sys.stderr)return Nonereturn s.data# 清空链栈(保留栈结构,仅清空元素)
def clear_stack(s):# 遍历并释放所有节点(Python中无需手动释放,只需将栈顶置空)return None# 销毁链栈(释放所有资源)
def destroy_stack(s):# 链栈在Python中无需额外销毁操作,清空即可return clear_stack(s)# 遍历链栈元素(从栈顶到栈底)
def traverse_stack(s):if stack_empty(s):print("栈为空,无元素可遍历!")returnprint("链栈元素(从栈顶到栈底):", end="")p = swhile p is not None:print(p.data, end=" ")p = p.nextprint()# 复制栈(将S复制到T)
def copy_stack(s):t = init_stack()if stack_empty(s):return t# 辅助栈用于临时存储元素(解决顺序问题)temp = init_stack()p = s# 先将S的元素逆序存入临时栈while p is not None:temp = push(temp, p.data)p = p.next# 再将临时栈的元素存入T,恢复原顺序while not stack_empty(temp):val, temp = pop(temp)t = push(t, val)return t# 判断两个栈是否相等(元素数量和对应位置元素都相同)
def stack_equal(s, t):# 长度不同则直接不相等if stack_length(s) != stack_length(t):return Falsep, q = s, twhile p is not None and q is not None:if p.data != q.data:return Falsep = p.nextq = q.nextreturn True# 逆置链栈(改变元素顺序)
def reverse_stack(s):if stack_empty(s) or stack_length(s) == 1:return s # 空栈或只有一个元素无需逆置prev = Nonecurr = snext_node = None# 反转链表指针方向while curr is not None:next_node = curr.next # 保存下一个节点curr.next = prev # 反转当前节点指针prev = curr # 移动prev到当前节点curr = next_node # 移动curr到下一个节点return prev # 返回新的栈顶指针# 测试函数
def main():import sys# 初始化栈s = init_stack()t = init_stack()print(f"初始化链栈S后,栈是否为空:{'是' if stack_empty(s) else '否'}")# 进栈操作print("\n执行进栈操作:依次入栈 10, 20, 30, 40, 50")s = push(s, 10)s = push(s, 20)s = push(s, 30)s = push(s, 40)s = push(s, 50)traverse_stack(s)print(f"栈S的长度:{stack_length(s)}")# 复制栈操作print("\n复制栈S到栈T...")t = copy_stack(s)print("栈T的元素:", end="")traverse_stack(t)print(f"栈S和栈T是否相等:{'是' if stack_equal(s, t) else '否'}")# 逆置栈操作print("\n逆置栈S...")s = reverse_stack(s)print("逆置后栈S的元素:", end="")traverse_stack(s)print(f"栈S和栈T是否相等:{'是' if stack_equal(s, t) else '否'}")# 再次逆置恢复原顺序s = reverse_stack(s)print("再次逆置后栈S的元素:", end="")traverse_stack(s)# 出栈和取栈顶操作print("\n执行出栈操作:")val, s = pop(s)print(f"出栈元素:{val}")val, s = pop(s)print(f"出栈元素:{val}")traverse_stack(s)print(f"当前栈顶元素:{get_top(s)}")print(f"当前栈S的长度:{stack_length(s)}")# 清空栈操作print("\n清空栈S...")s = clear_stack(s)print(f"清空后栈S是否为空:{'是' if stack_empty(s) else '否'}")print(f"清空后栈S的长度:{stack_length(s)}")# 测试栈Tprint("\n栈T的元素:", end="")traverse_stack(t)print(f"栈T的长度:{stack_length(t)}")# 销毁栈print("\n销毁链栈...")s = destroy_stack(s)t = destroy_stack(t)print(f"销毁后,栈S是否为空:{'是' if stack_empty(s) else '否'}")print(f"销毁后,栈T是否为空:{'是' if stack_empty(t) else '否'}")if __name__ == "__main__":main()
(三)Java代码
import java.util.Scanner;public class LinkStack {// 定义栈节点内部类private static class StackNode {int data; // 数据域StackNode next; // 指针域,指向后继节点// 节点构造函数public StackNode(int data) {this.data = data;this.next = null;}}private StackNode top; // 栈顶指针// 链栈的初始化public LinkStack() {top = null; // 栈顶指针置空,表示空栈}// 判断链栈是否为空public boolean stackEmpty() {return top == null;}// 求链栈的长度public int stackLength() {int length = 0;StackNode p = top;while (p != null) {length++;p = p.next;}return length;}// 链栈进栈操作public void push(int e) {StackNode p = new StackNode(e); // 创建新节点p.next = top; // 新节点指向原栈顶top = p; // 更新栈顶指针为新节点}// 链栈出栈操作public int pop() {if (stackEmpty()) {System.err.println("错误:栈为空,无法执行出栈操作!");return -1; // 栈空时返回特殊值}StackNode p = top; // 暂存栈顶节点int e = p.data; // 获取栈顶元素值top = top.next; // 更新栈顶指针p.next = null; // 帮助垃圾回收return e; // 返回出栈元素}// 取链栈栈顶元素public int getTop() {if (stackEmpty()) {System.err.println("错误:栈为空,无栈顶元素!");return -1; // 栈空时返回特殊值}return top.data; // 返回栈顶元素值}// 清空链栈(保留栈结构,仅清空元素)public void clearStack() {top = null; // 栈顶指针置空,Java垃圾回收会自动清理节点}// 销毁链栈(释放所有资源)public void destroyStack() {clearStack(); // 清空栈元素,Java无需额外操作}// 遍历链栈元素(从栈顶到栈底)public void traverseStack() {if (stackEmpty()) {System.out.println("栈为空,无元素可遍历!");return;}System.out.print("链栈元素(从栈顶到栈底):");StackNode p = top;while (p != null) {System.out.print(p.data + " ");p = p.next;}System.out.println();}// 复制栈(将当前栈复制到目标栈)public LinkStack copyStack() {LinkStack target = new LinkStack();if (stackEmpty()) {return target;}// 辅助栈用于临时存储元素(解决顺序问题)LinkStack temp = new LinkStack();StackNode p = top;// 先将当前栈的元素逆序存入临时栈while (p != null) {temp.push(p.data);p = p.next;}// 再将临时栈的元素存入目标栈,恢复原顺序while (!temp.stackEmpty()) {target.push(temp.pop());}return target;}// 判断两个栈是否相等(元素数量和对应位置元素都相同)public boolean stackEqual(LinkStack other) {// 长度不同则直接不相等if (this.stackLength() != other.stackLength()) {return false;}StackNode p = this.top;StackNode q = other.top;while (p != null && q != null) {if (p.data != q.data) {return false;}p = p.next;q = q.next;}return true;}// 逆置链栈(改变元素顺序)public void reverseStack() {if (stackEmpty() || stackLength() == 1) {return; // 空栈或只有一个元素无需逆置}StackNode prev = null;StackNode curr = top;StackNode next = null;// 反转链表指针方向while (curr != null) {next = curr.next; // 保存下一个节点curr.next = prev; // 反转当前节点指针prev = curr; // 移动prev到当前节点curr = next; // 移动curr到下一个节点}top = prev; // 更新栈顶指针}// 测试函数public static void main(String[] args) {LinkStack S = new LinkStack();LinkStack T = new LinkStack();// 初始化栈System.out.println("初始化链栈S后,栈是否为空:" + (S.stackEmpty() ? "是" : "否"));// 进栈操作System.out.println("\n执行进栈操作:依次入栈 10, 20, 30, 40, 50");S.push(10);S.push(20);S.push(30);S.push(40);S.push(50);S.traverseStack();System.out.println("栈S的长度:" + S.stackLength());// 复制栈操作System.out.println("\n复制栈S到栈T...");T = S.copyStack();System.out.print("栈T的元素:");T.traverseStack();System.out.println("栈S和栈T是否相等:" + (S.stackEqual(T) ? "是" : "否"));// 逆置栈操作System.out.println("\n逆置栈S...");S.reverseStack();System.out.print("逆置后栈S的元素:");S.traverseStack();System.out.println("栈S和栈T是否相等:" + (S.stackEqual(T) ? "是" : "否"));// 再次逆置恢复原顺序S.reverseStack();System.out.print("再次逆置后栈S的元素:");S.traverseStack();// 出栈和取栈顶操作System.out.println("\n执行出栈操作:");System.out.println("出栈元素:" + S.pop());System.out.println("出栈元素:" + S.pop());S.traverseStack();System.out.println("当前栈顶元素:" + S.getTop());System.out.println("当前栈S的长度:" + S.stackLength());// 清空栈操作System.out.println("\n清空栈S...");S.clearStack();System.out.println("清空后栈S是否为空:" + (S.stackEmpty() ? "是" : "否"));System.out.println("清空后栈S的长度:" + S.stackLength());// 测试栈TSystem.out.print("\n栈T的元素:");T.traverseStack();System.out.println("栈T的长度:" + T.stackLength());// 销毁栈System.out.println("\n销毁链栈...");S.destroyStack();T.destroyStack();System.out.println("销毁后,栈S是否为空:" + (S.stackEmpty() ? "是" : "否"));System.out.println("销毁后,栈T是否为空:" + (T.stackEmpty() ? "是" : "否"));}
}
四、程序运行结果展示
(一)C++程序运行截图
(二)Python程序运行截图
(三)Java程序运行截图
五、总结
链栈是一种基于链表实现的栈结构,具有先进后出(LIFO)的特性。其核心结构包括StackNode节点(含数据域和指针域)和栈顶指针LinkStack。主要操作包括初始化、判空、求长度、入栈、出栈、取栈顶元素等,时间复杂度多为O(1)。链栈的优势在于动态内存分配,无需预先确定容量,但需注意内存管理。此外,还支持高级操作如复制栈、判断栈相等、逆置栈等。本文提供了C++、Python和Java三种语言的完整实现代码及测试案例,展示了链栈的基本操作和运行结果。链栈适用于需要动态调整大小的场景,是数据结构中的重要实现方式。