本小节要进入另一个非常重要的数据结构 - 栈
1.栈的基本概念
- 栈是只允许在一端进行插入删除的线性表
- 栈顶(top):栈允许插入删除的那一端
- 栈底(bottom):压栈压栈就是压到栈底
- 栈的操作可以简单的看作后进先出(LIFO)
- n个不同的元素进栈,出栈的方式共有:
2.栈的基本操作 - 栈既然是线性表,那自然有顺序表和链表,也称之为顺序栈和链栈
- 顺序栈的实现:
#define MaxSize 50
typedef struct{
int data[MaxSize];
int top; //定义栈顶指针,用来指挥进栈和出栈
}SqStack;
栈顶指针:S.top,初始一般设置为S.top=-1
栈顶元素:S.data[S.top]
进栈操作:栈不满时,栈顶指针先进行+1操作,再写值入栈
出栈操作:栈不空时,先取栈顶元素,再执行栈顶指针-1(不好理解的画个栈看看进出栈元素变化和栈顶指针变化之间的关系)
栈空:S.top = -1
栈满:S.top = MaxSize-1 (线性表嘛,下标从0开始)
top指针最开始为-1,进栈先让top指针加一,指到正确的元素位置,再写元素;出栈先把值取出来,然后再让top指针减一。
- 初始化栈:
void initStack(SqStack &S){
s.top = -1;
}
- 进栈
int push(SqStack &S, int x){ //涉及到要修改数据结构元素、信息的,传参的时候加上地址符&
if(S.top==MaxSize-1)
return 0;
S.top++;
S.data[S.top] = x;
return 1;
}
- 出栈
int pop(SqStack &S, int x){
if(S.top==-1)
return 0;
x = S.data[S.top];
S.top--;
return x;
}
- 判断栈空
int isEmpty(SqStack S){
if(S.top==-1)
return 1;
return 0;
}
- 判断栈满
int isFull(SqStack S){
if(S.top==MaxSize-1)
return 1;
return 0;
}
- 读栈顶元素
int getTop(SqStack S){
if(S.top==-1)
return 0;
return S.data[S.top]
}
3.共享栈
- 让两个顺序栈共享一个数组,两个栈的栈底分别在数组的两端,栈顶可以在数组中动态扩展
共享栈的使用方法如图所示,当S0.top=-1时栈一为空,当S1.top=MaxSize-1时栈二为空栈满的条件就是两个栈的栈顶指针相邻,即S0.top+1=S1.top
对于左边的栈来说,进栈是让S0.top++,但是对于右边的栈来说元素进栈是让S1.top–。左边的栈元素进出和普通栈一样,但是右边的栈元素进出和普通栈是相反的。
有需求的时候画一个栈出来模拟推一下就行了。
4.链栈
栈虽然是受限的线性表,但也是线性表。线性表就有顺序存储和链式存储,栈也不例外。
栈是一端受限,因此用单链表就能很好的表示,在题目中遇到,就选定链头或者链尾插入或者删除元素就行了。怎么舒服怎么来吧~
定义方式:
typedef struct LinkNode{
int data;
struct LinkNode *next;
}*LiStack;
定义方式和单链表一样
5.典型例题
选D - 允许进出栈交替的话,看一个例子就行,比如a:abcd进,d出,c出,e进出,b出,f进出,a出。这样一推d选项连续三次出栈。其实看fedcb就行了,连续出栈好多次
选C - 队列:先进先出,因此也就是在说出栈的顺序其实是bdcfeag,a进,b进出(2),c进,d进出(3),c出,e进,f进,f出,e出,a出,g进出。没用稿纸,纯看着题目推,所以建议同学细心动手推一下,避免我口算有错,但是答案是正确的(抄个答案谁还不会了hhhhhh)
选B - 3+2=5,8-5=3,5*3=-15,我猜肯定有同学选A,错就错在第二步,一定要注意题目条件 b op a。一旦忽视这个条件肯定会算出负号来
选C - 1:解决某一问题必须使用某一数据结构99%是错的,毕竟for循环能以力破万法(狗头保命)。2:OS部分的内容,结合一下中断隐指令那部分(保存现场)。3:除非你说中途不允许出栈,不然就是n+1分之C2n n,可参考前面。4:那是队列
你以为栈就结束了吗?后面栈的应用才是要了亲命了~