一、栈的定义
栈的基本概念
1、栈是只能在一端进行插入和删除的线性表,进行插入和删除的一端称作“栈顶”,另一端称为“栈底”。没有元素的栈称为“空栈”。
2、栈的插入操作称为“入栈”, 栈的删除操作称为“出栈”。
3、特性:先进后出。
二、栈的基本运算
顺序栈
//顺序栈
//储存结构
#define MAXLEN 100
typedef int elementType;
typedef struct sStack{
elementType data[MAXLEN];//存放栈元素
int top;//栈顶指示器,与数组下标保持一致
}seqStack;
//初始化栈
void initialStack(seqStack &S){
//由于top与数组下标保持一致,top == 0时,表示栈中有一个元素
//因此,top == -1时,表示栈空
S.top = -1;
}
//判断栈空
bool StackEmpty(seqStack &S){
if (S.top == -1)
return true;
else
return false;
//也可简写:return (S.top == -1);
}
//判断栈满
bool StackFull(seqStack &S){
if (S.top == MAXLEN - 1)
return true;
else
return false;
//简写:return (S.top == MAXLEN - 1);
}
//取栈顶元素
bool stackTop(seqStack &S, elementType &x){
if (stackEmpty(S))
return false;//空栈,无法取栈顶元素
else{
x = S.data[top];
return true;
}
}
//入栈
bool pushStack(seqStack &S, elementType x){
if (stackFull(S))
return false;//栈满,无法再继续入栈
else{
S.top++;
S.data[S.top] = x;
//简写:S.data[++S.top];
}
}
//出栈
bool popStack(seqStack *S, elementType &x){
if (S.top == -1)
return false;//栈空
else{
x = S.data[S.top];
S.top--;
//简写:x = S.data[S.top--];
}
}
ps:这几种算法的时间复杂度都是O(1).
入栈前,一定要先判断是否栈满。出栈,取栈顶元素前,一定要判断是否栈空!
链栈
ps:本文采用不带头结点的单链表来实现
//链栈
//不带头结点的单链表实现
//存储结构
#define int elementType
typedef struct lsNode{
elementType data;//链栈的结点数据域
lsNode *next;//链栈的结点指针域
}sNode, *linkStack;
// 初始化栈
//栈顶指针和链栈的结点指针域是同种数据类型
void initialStack(sNode *&top){
top = NULL;
}
//判断栈空
bool stackEmpty(sNode *&top){
if (top == NULL)
return true;
else
return false;
}
//入栈
void pushStack(sNode *&top, elementType x){
sNode *s;
s = new sNode;
s->data = x;
s->next = top;
top = s;
}
//出栈
bool popStack(sNode *&top, elementType &x){
sNode *s;
if (top == NULL)
return false;//栈空,无法出栈
else{
s = top;
top = top->next;
x = s.data;//返回出栈的元素
delete s;
return true;
}
}
//释放链栈空间
void destroyStack(sNode *&top){
sNode *p = top;
sNode *s;
//当指针p不为空
while (p){
s = p;//保留p所指向的结点
p = p->next;
delete s;
}
top = NULL;//防止出现野指针
}
ps: 千万要注意,由于使用的是不带头结点的单链表实现链栈,所以在传入栈顶指针时要用*&top, 如果使用*top, 则会导致在子函数中改变了top的值,而主调函数中的top仍然指向之前的位置。