栈和队列
文章目录
栈(Stack)
后进先出(LIFO)Last In First Out
栈的顺序存储结构(SqStack——Sequence Stack)
表示方法
#define MaxSize 10;
typedef struct SqStack {
ElemType data[MaxSize];
int top; // 栈顶指针,指向栈顶数组的下标,而非位序
}SqStack;
SqStack S;
-
栈顶指针:S.top,初始时 S.top = -1;
-
栈顶元素:S.data[S.top];
-
进栈操作(push):由于是顺序表,有最大存储空间限制,栈不满时,栈顶指针加 1,送值到栈顶元素。
-
出栈操作(pop):出栈先判断是否空栈,非空,先取出栈顶元素,后栈顶指针减 1。
-
栈空条件:S.top = -1;
-
栈满条件:S.top = MaxSize - 1;
-
栈的当前长度:S.top + 1;
基本操作
初始化 InitStack(SqStack &S)
InitStack(SqStack &S) {
S.top = -1; // 栈顶指针置为 -1,当第一个元素进栈,指针 + 1,便指向下标 0,即数组第一元素
}
判栈空 StackEmpty(SqStack S)
bool StackEmpty(SqStack S) {
if (S.top == -1)
return true;
else
return false;
}
进栈 Push(SqStack &S, ElemType x)
bool Push(SqStack &S, ElemType x) {
if (S.top == MaxSize - 1)
return false; // 栈满
S.top++;
S.data[S.top] = x; // 两步并一步:S.data[++S.top] = x;
return true;
}
出栈 Pop(SqStack &S, ElemType &x)
bool Pop(SqStack &S, ElemType &x) {
if (S.top == -1)
return false; // 栈空
x = S.data[S.top--]; // 先返回,再减 1。【注】看变量和 ++ / -- 的位置,在前先执行。变量在前先返回。
return true;
}
读栈顶元素 GetTop(SqStack &S, ElemType &x)
bool GetTop(SqStack &S, ElemType &x) {
if (S.top = -1)
return false; // 栈空读取不到任何元素。
x = S.data[S.top];
return true;
}
读栈顶其实就是在判断栈是否为空罢了。
共享栈
栈 0 从前向后移动,栈 1 从后先前移动。
typedef struct SqStack {
ElemType data[MaxSize];
int top0;
int top1;
}SqStack;
-
栈顶指针:初始时,S.top0 = -1; S.top1 = MaxSize;
-
栈顶元素:S.data[S.top0]; S.data[S.top1];
-
进栈操作(push):
- 栈 0:栈顶指针加 1,再存数。
- 栈 1:栈顶指针减 1,再存数。
-
出栈操作(pop):
- 栈 0:取数,栈顶指针减 1
- 栈 1:取数,栈顶指针加 1
-
栈空:
- 栈 0:S.top0 = -1;
- 栈 1:S.top1 = MaxSize;
-
栈满:S.top0 = S.top1 - 1;
-
栈当前长度:
- 栈 0:S.top0 + 1;
- 栈 1:MaxSize - S.top1;
栈的链式存储结构(LiStack——LinkStack)
链式存储没有最大长度 MaxSize 的限制,不存在栈满上溢情况。
链式存储的栈使用单链表、双链表都可以实现,双链表实现非常简单,但是存储密度不高,一般使用单链表。
栈的特点是后进先出,如果我们在单链表的尾部进栈,则栈顶指针指向尾部,进栈时,可以实现栈顶指针“先加 1”,再添加数据元素的操作;但是在出栈时,由于是单链表,数据元素取出后,栈顶指针无法“减 1”,因此在表尾进行操作并不合理。
所以基本操作都在表头实现,这时,回想前面单链表中的头插法,恰好满足了“后进先出”的特点。
表示方法
typedef struct Linknode {
ElemType data;
struct Linknode *next;
} *LiStack;
LiStack p 等价于 Linknode *p,前者强调栈,后者强调数据元素。
- 栈顶指针:S 即单链表的第一个数据元素的地址,也就是栈顶地址,S 可看作栈顶指针。
基本操作
只需操作栈顶,因此使用不带头结点的单链表更加方便~
初始化:InitStack(LiStack &S)
void InitStack(LiStack S) {
S = NULL;
}
判栈空:StackEmpty(LiStack S)
bool StackEmpty(LiStack S) {
if (S == NULL)
return true;
}
进栈:Push(LiStack &S, Linknode *p)
bool Push(LiStack S, Linknode *p) {
if (p == NULL)
retur