文章目录
栈的存储
类似于线性表的顺序表和链表,栈也分为顺序栈和链栈。这都源于两类存储方式——顺序存储&链式存储。
顺序存储
定义
采用顺序存储的栈称之为顺序栈,它利用一组地址连续的存储单元存放自栈底到栈顶的数据元素,同时设立一个指针(top)指示当前栈顶元素的位置。
代码实现
//顺序栈的定义
#define MaxSize 10 //定义栈中元素的最大个数
typedf struct{ //
Elemtype data[MaxSize]; // 静态数组存放栈中元素
int top; //栈顶指针
}SqStack;
//Sq:sequence-顺序
对于typedf与结构体不太了解的可以参考我的这篇文章:结构体——typedf——顺序表——单链表
void testStack(){
SqStack S; //声明一个顺序栈(并为之分配空间)
//...后续操作...
栈顶指针与栈中元素在内存中的存储
当为上述SqStack S语句执行完毕后,内存中会进行分配空间。
顺序存储:给各个数据元素分配连续的存储空间,大小为:
M
a
x
S
i
z
e
∗
s
i
z
e
o
f
(
E
l
e
m
T
y
p
e
)
MaxSize*sizeof(ElemType)
MaxSize∗sizeof(ElemType)
注意到:top指针也占另外的4B内存,且指向栈顶元素所在的位置。
初始化栈及其代码
初始化栈,要分配指针,且栈顶元素为S.data[S.top]。
//顺序栈的定义
#define MaxSize 10 //定义栈中元素的最大个数
typedf struct{ //
Elemtype data[MaxSize]; // 静态数组存放栈中元素
int top; //栈顶指针
}SqStack;
//初始化栈
void InitStack(SqStack &S){
S.top=-1;//初始化栈顶指针,开始栈中无元素。
}
判断栈空及其代码
判断栈是否为空,只需要判断栈顶元素所对应的指针是否为-1即可。
//顺序栈的定义
#define MaxSize 10 //定义栈中元素的最大个数
typedf struct{ //
Elemtype data[MaxSize]; // 静态数组存放栈中元素
int top; //栈顶指针
}SqStack;
//函数功能:判断栈空
bool StackEmpty(SqStack S){
if(S.top=-1);//栈空
return ture;
else //不空
return false;
}
进栈操作及其代码
//顺序栈的定义
#define MaxSize 10 //定义栈中元素的最大个数
typedf struct{ //
Elemtype data[MaxSize]; // 静态数组存放栈中元素
int top; //栈顶指针
}SqStack;
//函数功能——新元素x入栈
bool Push(SqStack &S,ElemType x){
if(S.top==MaxSize-1)//栈满,报错
return false;
S.top=S.top+1; // 栈指针先加一
S.data[S.top]=x; //新元素入栈
return ture;
}
—————————————————————等价于————————————————————
//函数功能——新元素x入栈
bool Push(SqStack &S,ElemType x){
if(S.top==MaxSize-1)//栈满,报错
return false;
S.data[++S.top]=x; //栈指针先加一,新元素入栈。top值先加一,再使用top的指针放入新元素
return ture;
}
出栈操作及其代码
//顺序栈的定义
#define MaxSize 10 //定义栈中元素的最大个数
typedf struct{ //
Elemtype data[MaxSize]; // 静态数组存放栈中元素
int top; //栈顶指针
}SqStack;
//函数功能——栈顶元素出栈
bool Pop(SqStack &S,ElemType &x){
if(S.top==-1)//栈中无元素,不存在出栈;
return false;
x=S.data[S.top];//栈顶元素先出栈
S.top=S.top-1; // 栈指针再减一
return ture;
}
注意:上述操作只是在逻辑上被删除了,原来的栈顶元素数据信息还在内存中
—————————————————————等价于————————————————————
//函数功能——栈顶元素出栈
bool Pop(SqStack &S,ElemType &x){
if(S.top==-1)//栈空,报错
return false;
x=S.data[S.top--] //栈顶元素先出栈.栈指针再减1;先使用top的值获得对应的栈顶元素,然后top的值再减一。
return ture;
}
读取栈顶元素操作及其代码
读取栈顶元素操作与出栈操作类似,可以对比学习。
读栈操作不会对top指针进行改变,出栈操作会这样。
//顺序栈的定义
#define MaxSize 10 //定义栈中元素的最大个数
typedf struct{ //
Elemtype data[MaxSize]; // 静态数组存放栈中元素
int top; //栈顶指针
}SqStack;
//函数功能——栈顶元素出栈
bool Pop(SqStack &S,ElemType &x){
if(S.top==-1)//栈空,报错
return false;
x=S.data[S.top--]; //栈顶元素先出栈.栈指针再减1;先使用top的值获得对应的栈顶元素,然后top的值再减一。
return ture;
}
//函数功能———读栈顶元素
bool GetTop(SqStack &S,ElemTyp e &x){
if(S.top==-1)//栈空,报错
return false;
x=S.data[S.top]; //x记录栈顶元素数据信息
return ture;
}
**思考:**如果我们在初始化top不是-1而变为0了呢,那么代码就会改变。
顺序栈的缺点
- 栈的大小不可变,解决方法:链式栈
- 刚开始用很大的内存空间不太合理-共享栈的提出
共享栈
定义:
利用栈底位置的相对不变的特性,可以让两个顺序栈共享一个一维数组空间,将两个栈的栈底分别设置在栈共享空间的两端,两个栈顶向共享空间的中间延伸。
简单来说就是两个栈共享同一片空间。
图片引用https://www.itdaan.com/blog/2017/08/27/3c5aa7833640180ccba7ea91ebb94a7a.html
//顺序共享栈的定义
#define MaxSize 10 //定义栈中元素的最大个数
typedf struct{ //
Elemtype data[MaxSize]; // 静态数组存放栈中元素
int top1; //1号栈指针
int top2; //2号栈指针
}ShStack;
//初始化共享栈
void InitStack(ShStack &S){
S.top1=-1;
S.top2=MaxSize;
}
共享栈的特性
采用共享栈的好处:
节省存储空间,降低发生上溢的可能性
共享栈栈满的条件:
top1+1==top2
注意:
栈满还存为上溢,栈空还取为下溢
链式存储
定义
采用链式存储的栈称为链栈
链栈的优点
- 便于多个栈共享存储空间和提高其效率且不存在栈满溢出的情况;
- 通常采用单链表实现,并规定所有操作都是在单链表的表头进行;
- 规定链栈没有头结点,Lhead指向栈顶元素;
4.链头的一端等于栈顶的一端;
可以复习单链表的有关操作:单链表上基本操作的实现——建立,插入,查找,删除,表长。
链栈的链式存储类型
typedef struct Linknode{
ElemType data; //数据域
struct Linknode *next; //指针域
}*LiStack;
我们在学习单链表的过程中会分为带头结点与不带头结点的情况放在这里亦是如此。
一般而言,在使用链栈的过程中,默认使用不带头结点的情况。