链式栈
链式栈是栈的链式存储结构,它主要通过链表来实现栈的操作。在链式栈中,每个节点包含两部分:一部分是存储数据的数据域,另一部分是指向下一个节点的指针域。链式栈通常包含以下基本操作:创建栈、栈的入栈操作(Push)、栈的出栈操作(Pop)、判断栈空、获取栈顶元素、销毁栈。
1. 定义链式栈的节点结构体
typedef struct StackNode {
int data; // 数据域
struct StackNode* next; // 指针域
} StackNode, *LinkStack;
2. 创建栈
创建栈本质上是初始化栈顶指针。
void InitStack(LinkStack* top) {
*top = NULL;
}
3. 入栈操作(Push)
void Push(LinkStack* top, int e) {
StackNode* newNode = (StackNode*)malloc(sizeof(StackNode));
newNode->data = e;
newNode->next = *top;
*top = newNode;
}
4. 出栈操作(Pop)
int Pop(LinkStack* top, int* e) {
if (*top == NULL) return 0; // 栈为空
StackNode* temp;
*e = (*top)->data;
temp = *top;
*top = (*top)->next;
free(temp);
return 1;
}
5. 判断栈空
int IsEmpty(LinkStack top) {
return top == NULL;
}
6. 获取栈顶元素
int GetTop(LinkStack top, int* e) {
if (top == NULL) return 0; // 栈为空
*e = top->data;
return 1;
}
7. 销毁栈
void DestroyStack(LinkStack* top) {
StackNode* temp;
while (*top != NULL) {
temp = *top;
*top = (*top)->next;
free(temp);
}
}
以上是链式栈的基本操作。在实际应用中,这些操作可根据具体需求进行调整和扩展。链式栈的优点是不需要事先指定栈的大小,它可以动态地进行内存分配,但每个节点需要额外的空间来存储指针。总体代码如下:
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
typedef struct LinkStack{
int data;
struct LinkStack *next;
};
//初始化
void Init_Stack(LinkStack *&S)
{
S=(LinkStack *)malloc(sizeof(LinkStack));
S->next=NULL;
}
//进栈
int push_Stack(LinkStack *&S,int e)
{
LinkStack *s;
s=(LinkStack *)malloc(sizeof(LinkStack));
s->data=e;
s->next=S->next;
S->next=s;
}
//出栈
int pop_Stack(LinkStack *&S,int &e)
{
LinkStack *s;
if(S->next==NULL)
return 0;
s=(LinkStack *)malloc(sizeof(LinkStack));
s=S->next;
e=s->data;
S->next=s->next;
free(s);
return 1;
}
//显示
int show_Stack(LinkStack *S)
{
LinkStack *p;
p=S->next;
while(p!=NULL)
{
printf("%d ",p->data);
p=p->next;
}
}
int main()
{
LinkStack *S;
Init_Stack(S);
push_Stack(S,1);
push_Stack(S,2);
push_Stack(S,3);
show_Stack(S);
int a=0;
pop_Stack(S,a);
show_Stack(S);
printf("%d",a);
}
常用场景:
1. 函数调用栈
在计算机程序中,函数调用经常使用栈来管理。每当一个函数被调用时,其参数、返回地址及局部变量被压入栈中,当函数执行完成后,这些信息被弹出栈。链式栈可以动态地管理这种栈空间,特别是在嵌套或递归函数调用较多的情况下。
2. 表达式求值
链式栈被广泛用于算术或逻辑表达式的求值,特别是在处理复杂表达式(包括中缀、前缀和后缀表达式)的转换和计算中。栈用于存储操作数和操作符,以及在整个求值过程中临时保存中间结果。
3. 括号匹配
在编程语言中,链式栈可以用来检查括号(如圆括号、方括号、花括号)是否正确匹配。每次遇到开放括号时,将其压入栈中;遇到闭合括号时,检查并弹出栈顶的开放括号,以判断括号是否成对出现。
4. 逆序输出
链式栈可用于实现数据的逆序输出。例如,字符串或数字的逆序打印,通过将字符或数字依次压入栈中,然后弹出,就可以实现逆序输出。
5. 回溯算法
在解决某些递归问题时,如深度优先搜索(DFS)、迷宫问题、八皇后问题等,链式栈可以用于实现回溯算法,记录搜索路径和状态,方便在退回到上一步时恢复状态。
6. 页面历史记录
在浏览器中,链式栈可以用来管理用户的页面访问历史。每次用户访问新页面时,地址被压入栈中。当用户点击后退按钮时,可以从栈中弹出最近访问的页面地址。
7. 语法分析
在编译器设计中,链式栈可用于语法分析阶段,特别是在实现某些解析算法(如LL(1)分析、LR分析)时,用于存储待分析的符号和状态。
8. 逆波兰表达式(后缀表达式)计算
在计算机科学中,逆波兰表达式的计算经常使用栈。链式栈可以用于存储操作数,遇到操作符时进行相应的计算。