目录
1.重点:
栈的特性:后进先出(先进后出)
只能在栈顶进行插入和删除,后面一系列操作将围绕这两大特点展开
进栈出栈逻辑图
2.顺序栈
顺序栈实质就是一个静态顺序表,一种操作受限的静态顺序表,重点掌握前面章节的顺序表,该操作便很容易上手,提供个写顺序栈的代码,就不进行代码思路图讲解咯
定义顺序栈
用数组实现,看着人模狗样的,实质就是个数组,不过是操作受限而已,了解有这么些概念即可,重点要理解后面的实际应用场景
typedef int TypeData;
//定义一个顺序栈
typedef struct SeqStack
{
TypeData arr[MAX];
int top;
}SeqStack;
增(也只能在栈顶进行操作,注意栈顶下标的加减即可)
判断顺序栈是否已满
//增
void StackPush(SeqStack* p, int x)
{
if (p->top == MAX)
{
printf("顺序栈已满,插入失败\n");
return;
}
printf("插入成功\n");
p->arr[p->top] = x;
p->top++;
}
删(注意栈顶下标是先见在删还是先删在减,前面初始化值不同该操作也略有不同)
//删
void StackPop(SeqStack* p)
{
if (p->top == 0)
{
printf("顺序栈为空,删除失败\n");
return;
}
printf("删除成功\n");
p->top--;
p->arr[p->top] = 0;
}
查(从栈顶开始遍历到栈底便可)
//查
void StackSearch(SeqStack* p, int x)
{
for (int i = 0; i < p->top; i++)
{
if (p->arr[i] == x)
{
printf("该顺序栈含有%d\n", x);
return;
}
}
printf("找不到\n");
}
共享栈(特例)
实质为一种特殊的顺序栈 (了解)
3.链栈
链栈实质为只能进行头插和头插的链表,即操作受限的链表
重点掌握前面链表章节即可(了解有这么个概念)
定义链栈
//定义链栈
typedef struct LinkStack
{
TypeData x;
struct LinkStack* next;
}LinkStack, Node;
增(只能栈顶增加元素即只允许头插)
void LinkStackPush(LinkStack* p, int x)
{
//因为栈只允许从栈顶插入,所以只允许头插
//因为有需要便开辟新节点头插进行存储数据,基本不会存在链栈存满情况
assert(p);
//开辟新节点
Node* newnode = (Node*)malloc(sizeof(Node));
assert(newnode);
newnode->x = x;
newnode->next = p->next;
p->next = newnode;
}
删(只运行在栈顶进行操作即只能头删)
void LinkStackPop(LinkStack* p)
{
//因为栈只允许从栈顶删除,所以只允许头删
assert(p);
//判断链栈是否为空
if (p->next == NULL)
{
printf("链栈为空\n");
return;
}
Node* ptem = p->next;
p->next = ptem->next;
free(ptem);
}
4.栈的应用场景(重点)
1. 操作符栈
栈在括号中的匹配应用
2.表达式求值
该场景让我们加深理解栈区的空间是如何重复利用的,但机器计算都是运用后缀表达式求值,故 我们要将中值表达式化为后缀表达式求值,化的过程注意操作符的优先级
前缀表达式求值
后缀表达式求值(机算逻辑)
3.栈在函数递归中的应用