栈
栈的数据存储满足“后进先出的原则”,与函数的递归调用具有相同的性质。
1.栈的存储结构
顺序栈的存储结构
typedef int ElemType;
typedef struct {
ElemType data[MaxSize];
int top;
}SqStack;
链式栈的存储结构
typedef int ElemType;
typedef struct StackNode{
ElemType data;
struct StackNode *next;
}StackNode, *LinkStack;
2.栈的初始化
顺序栈的初始化
顺序栈的数据存储部分是由数组构成,只需要令其中的栈顶指针等于-1,则完成了顺序栈的初始化。
void InitStack(SqStack &S){
/*初始化顺序栈*/
S.top = -1;
}
链式栈的初始化
由于链式栈采用链表结构进行存储,其中不需要对栈进行初始化,只需要定义栈的头指针即可,即头指针指向的是栈顶的元素,当顺序栈为空时,其头指针等于NULL;链式栈同时也不需要头节点。
LinkStack S; //定义链式栈的头指针
2.入栈操作
顺序栈的入栈操作
顺序栈的入栈只需要将数据存储到data数组,并将代表头节点的top指针自增即可。
bool Push(SqStack &S, ElemType e){
/*入栈操作*/
//1.判断是否栈满
if (S.top == MaxSize-1)
return false;
//2.入栈
S.data[++S.top] = e;
return true;
}
链式栈的入栈操作
链式栈需要建立新的数据结点p,将p的next指针指向S栈顶指针,再将栈顶指针移动到首位,即可完成入栈操纵;
bool Push(LinkStack &S, ElemType e){
/*入栈操作*/
//1.生成新结点
StackNode *p = (LinkStack)malloc(sizeof(StackNode));
//2.插入新结点
p->data = e;
p->next = S;
S = p;
return true;
}
3.出栈操作
顺序栈的出栈操作
顺序栈出栈需要判断栈是否为空后,将栈顶元素通过引用返回,其中判断top指定是否为-1来判断栈是否为空,并将top指针自减即可;
bool Pop(SqStack &S, ElemType &e){
/*出栈操作*/
//1.判断是否栈空
if (S.top == -1)
return false;
//2.出栈
e = S.data[S.top--];
return true;
}
链式栈的出栈操作
链式栈判断为空的条件为S头指针是否为NULL,后只需要将S指针后移即可完成;
bool Pop(LinkStack &S, ElemType &e){
/*出栈操作*/
//1.判断栈空
if (S == NULL)
return false;
//2.出栈
StackNode *p = S;
e = p->data;
S = S->next;
free(p);
return true;
}
4.获取栈顶元素操作
顺序栈获取栈顶元素
顺序栈获取栈顶元素与其出栈操作类似,但是不需要操作top指针,也就是结点不需要删除;
bool GetTop(SqStack S, ElemType &e){
/*获取栈顶元素*/
//1.判断是否栈空
if (S.top == -1)
return false;
//2.获取栈顶元素
e = S.data[S.top];
return true;
}
链式栈获取栈顶元素
链式栈获取栈顶元素也与其出栈操作类似,其S指针不动,即可完成操作;
bool GetTop(LinkStack S, ElemType &e){
/*获取栈顶元素*/
if (S == NULL)
return false;
e = S->data;
return true;
}