栈其实就是一种插入和删除操作受限的线性表
在线性表中,插入和删除操作可以在任意位置进行,而在栈中,只能在一端进行,即只能在表尾插入和删除
栈是后进先出的一种数据结构,即后面入栈的元素反而先出栈(LIFO)
栈有空栈,即没有任何元素
栈的栈顶和栈底指的是栈的可以插入元素的一端和栈的不可以插入元素的一端
所以,栈这个数据结构的逻辑操作和线性表一样,只不过数据的运算:即插入和删除有所不同
在查找栈时,大多数只要查找栈顶元素即可
栈的题型:告诉你入栈顺序,考你有哪些合法的出栈顺序
一般出选择题,可以自行判断
注意:有时候是入栈和出栈一起进行的,比如a,b入栈,b出栈后再c,d,e入栈,后c,d,e出栈,a也出栈
- 顺序栈的实现
1.定义
#define MaxSize 10
typedef struct {
ElemType data[MaxSize]; //静态数组存放栈中元素
int top; //栈顶指针,从-1开始
}SqStack;
所需分配的内存空间为:Maxsize*sizeof(ElemType)
为什么top指针要从-1开始指:因为我们刚开始创建的是一个空栈,没有任何元素,所以top指针从-1开始指比较好
2.初始化栈
void InitStack(SqStack &s) {
s.top=-1;
}
3.判断栈是否为空
bool StackEmpty(SqStack &s) {
if(s.top==-1) return true;
else return false;
}
4.入栈操作
bool push(SqStack &s,ElemType x) {//x为所要插入元素
if(s.top==Maxsize-1) return false;//栈满,报错
s.top=s.top+1;//先让指针指向栈顶(先假设已经加了)
s.data[s.top]=x;//新元素入栈
return true;
}
5.出栈操作
bool pop(SqStack &s,ElemType &x) {//这里的x要用引用,因为要与定义的x同步
if(s.top==-1) return false;//栈空,报错
x=s.data[s.top];//栈顶元素先出栈
s.top-=1;
return true;
}
6.读取栈顶元素
bool GetTop(SqStack &s,ElemType &x) {
if(s.top==-1) return false;
x=s.data[s.top];
return true;
}
注意:如果top在初始化时为0,那么就是让top指针指向下一个要插入元素的位置
顺序栈的缺点:栈的大小不可变
共享栈
即两个指针,一个指向栈底,一个指向栈底
链栈的实现
链栈实际上就是插入和删除受限的单链表
单链表的表头相当于栈顶,所以我们都是对表头进行插入和删除的
即使用头插法
typedef struct Linknode {
ElemType data;
struct Linknode *next;
}*LiStack;//这里写的是不带头节点的链栈