栈的基本概念
数据结构的三要素 – 逻辑结构、数据运算、存储结构 。
(存储结构存储结构不同,运算的实现方式不同。)
栈 (Stack)是只允许在一端进行插入或删除操作的线性表
。即栈是一种线性表,但限定这种线性表只能在某一端进行插入和删除操作。
栈顶
(Top):线性表允许插入删除的那一端。
栈底
(Bottom):固定的,不允许进行插入和删除的一端。
空栈
:不包含任何元素的栈。
栈道操作特性
:后进先出(Last In First Out,LIFO)。
栈的数学性质
: $n$个不同元素进栈,出栈元素不同排列的个数为$\frac1{n+1}C^n_{2n}$。上述公式称为卡特兰(Catalan)数,可采用数学归纳法证明。
栈道基本操作:
InitStack(&S)
:初始化栈。构造一个空栈S,分配内存空间。
DestroyStack(&S)
:销毁栈,并释放栈S所占用的内存空间。
Push(&S, x)
:进栈,若栈S未满,则将x加入使之成为新栈顶。
Pop(&S, &x)
:出栈,若栈S非空,则弹出栈顶元素,并将x返回。
GetTop(S, &x)
:读取栈顶元素。若栈S非空,则用x返回栈顶元素。
StackEmpty(S)
:判断栈S是否为空。若S为空,则返回true,否则返回false
顺序栈的定义
1 2 3 4 5
| #define MaxSize 10 typedef struct { int data[MaxSize]; int top; }SequenceStack;
|
栈的初始化:
1 2 3 4 5 6 7 8
|
void InitStack(SequenceStack& S) { S.top = -1; }
|
栈的判空:
1 2 3 4 5 6 7 8 9 10 11 12 13
|
bool isEmpty(SequenceStack S) { if (S.top = -1) { return true; } else { return false; } }
|
入栈:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
bool Push(SequenceStack& S, int e) { if (S.top == MaxSize - 1) { printf("栈已满"); return false; } S.top += 1; S.data[S.top] = e; return true; }
|
出栈:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
bool Pop(SequenceStack& S, int& e) { if (S.top = -1) { printf("栈已空,无元素返回"); return false; } e = S.data[S.top]; S.top -= 1; return true; }
|
获取栈顶元素:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
bool GetTop(SequenceStack S, int& e) { if (S.top == -1) { printf("栈已空,无元素返回"); return false; } e = S.data[S.top]; return true; }
|
由静态数组定义的栈空间,使用结束后系统会自动回收。
共享栈的定义
1 2 3 4 5 6
| #define MaxSize 10 typedef struct { int data[MaxSize]; int top0; int top1; }ShareStack;
|
共享栈的初始化:
1 2 3 4 5 6 7 8 9
|
void InitStack(ShareStack& S) { S.top0 = -1; S.top1 = MaxSize; }
|
共享栈判空:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
bool isEmpty(ShareStack S, int type) { if (type == 0) { if (S.top0 == -1) { return true; } } if (type == 1) { if (S.top1 == MaxSize) { return true; } } return false; }
|
共享栈入栈:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
bool Push(ShareStack& S,int type, int e) { if (type == 0) { if (S.top0 + 1 == S.top1 ) { printf("共享栈已满"); return false; } S.top0++; S.data[S.top0] = e; return true;
} if (type == 1) { if (S.top0 + 1 == S.top1 ) { printf("共享栈已满"); return false; } S.data[S.top1] = e; S.top1--; return true; } return false; }
|
共享栈出栈:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
bool Pop(ShareStack& S, int type, int& e) { if (type == 0) { if (S.top0 == -1 ) { printf("共享栈为空"); return false; } e = S.data[S.top0]; S.top0--; return true;
} if (type == 1) { if (S.top1 == MaxSize) { printf("共享栈为空"); return false; } e = S.data[--S.top1]; return true; } return false; }
|
由静态数组定义的栈空间,使用结束后系统会自动回收。
链式存储的栈
采用链式存储的栈称为链栈
,链栈的有点是便于多个栈共享存储空间和提高其效率,且不存在栈满上溢的情况。通常采用单链表实现,并规定所有操作都是在单链表的表头进行的。这规定链栈没有头节点,LHead指向栈顶元素。
链栈的定义:
1 2 3 4
| typedef struct Linknode{ int data; struct Linknode *next; }*LinkStack;
|
采用链式存储,便于结点的插入与删除。链栈道操作与链表类似,入栈和出栈的操作都在链表的表头进行(头插法)。
需要注意的是不带头节点和带头节点的链栈道具体实现会有所不同。