什么是栈?
[TOC]
一、栈的基本概念
1.栈的定义
**栈(stack)**是一种线性表,这种线性表只在一端进行插入或者删除。可以形象地理解为平时吃的罐装的乐事薯片,只能从开口拿出或者放入薯片。
栈又称为后进先出(Last In Frist Out)的线性表,简称LIFO结构
**栈顶(top)**:线性表允许插入的那一端。
**栈底(bottom)**:不允许插入和删除的那一端,与栈顶相对。
2.栈的常见基本操作
·InitStack(&S):初始化一个空栈S。
·StackEmpty(S):判断一个栈是否为空,若为空则返回true否则返回false
·Push(&S,x):进栈(栈的插入操作),若栈未满则将x加入使之成为新栈顶
·pop(&S,&x):出栈(栈的删除操作),若栈S非空,则弹出栈顶元素,
·GetTop(S,&x):读取栈顶元素,若栈S非空,则用x返回栈顶元素。
·DestroyStack(&S):栈销毁,并释放S所占用的空间。(‘’&”表示引用调用)
二、栈的顺序储存结构
我们可以通过代码实现栈的插入、删除、判断栈是否为空、为满
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| #include <stdio.h> #include <stdlib.h>
#define MAX_SIZE 100
typedef struct { int data[MAX_SIZE]; int top; }Stack;
void initStack(Stack *stack) { stack->top = -1; }
int isEmpty(Stack *stack) { return stack->top == -1; }
int isFull(Stack *stack) { return stack->top == MAX_SIZE -1; }
void push(Stack *stack, int value) { if (isFull(stack)) { printf("栈已经满,无法入栈\n"); return ; } stack->data[++stack->top] = value; }
int pop(Stack *stack) { if (isEmpty(stack)) { printf("栈空,无法出栈\n"); exit(1); } return stack->data[stack->top--]; }
int top(Stack *stack) { if (isEmpty(stack)) { printf("栈空,无法获取栈顶元素\n"); exit(1); } return stack->data[stack->top]; }
int main() { Stack s1; push(&s1, 10); push(&s1, 20); push(&s1, 30); push(&s1, 40); push(&s1, 50); int topele; for (int i = 0; i < 5; i++) { topele = top(&s1); pop(&s1); printf("%d ", topele); } printf("\n"); }
|
根据顺序栈容量(数组大小)是否可以根据需要进行扩展,可以分为静态顺序栈和动态顺序栈。
A.静态顺序栈
不能根据需要增大栈的存储空间;
==静态数组arr一旦创建就无法改变大小(n)!==

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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| typedef struct sqstack{ ElemType stack_array[STACK_SIZE]; int top; int bottom; }SqStack;
SqStack Init_Stack(){ SqStack S; S.bottom = S.top = 0; return(S); }
Status push(SqStack &S, ElemType e){ if(S.top == STACK_SiZE - 1){ return ERROR; } S.top ++; S.stack_array[S.top] = e; S.stack_array[S.top] = e; S.top ++; return OK; }
Status pop(SqStack &S, ElemType *e){ if(S.top == S.bottom){ return ERROR; } *e = S.stack_array[S.top]; S.top --; return OK; }
|
B.动态顺序栈
可以根据需要增大栈的存储空间;
- 实现方法:采用动态一维数组:
T *P = new T[n];

==事实上,不管是静态|动态数组,空间一经分配,都无法更改大小!==
==只是动态数组由指针指向,程序后台帮助实现了[原数组.信息]的拷贝/迁移!==
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| typedef struct sqstack{ ElemType *bottom; ElemType *top; int stacksize; }SqStack;
Status Init_Stack(SqStack &S, int n){ S.bottom = new ElemType[n]; if(!S.bottom){ return ERROR; } S.top = S.bottom; S.stacksize = n; return OK; }
Status push(SqStack &S, ElemType e){ if((S.top - S.bottom) >= S.stacksize - 1){ if(!S.bottom){ return ERROR; } S.top = S.bottom + S.stacksize; S.stacksize += STACK_INCCREMENT; } return OK; }
Status pop(SqStack &S, ElemType *e){ if(S.top <= S.bottom){ return ERROR; } *e = *S.top; S.top --; return OK; }
|
三、共享栈
当我们需要用多个栈存放相同类型的数据的时候,容易会出现栈未满的情况,造成空间的浪费。共享栈就能很好的解决这个问题
概念
利用栈底位置相对不变的特征,可让两个顺序栈共享一个一维数组空间,将两个栈的栈底分别设置再共享栈的两端,两个栈顶向中间延伸。如图所示:

需要注意的是,top0=-1的时候1号栈为空,而top1=MaxSize1号栈为空;当两个栈的栈顶指针相邻,即top0+1=top1,栈满。对于0号栈来说,进栈的时候,top0先加1再赋值,出栈时先赋值后-1;对于1号栈来说,进栈的时候top1减1再赋值,出栈时先赋值后加。(具体课参考下面代码)
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| #include<stdio.h> #include<stdlib.h> #define MAXSIZE 50 typedef int ElemType; typedef struct{ ElemType data[MAXSIZE]; int top0; int top1; }sqDoubleStack;
void initSqDoubleStack(sqDoubleStack *s){ s->top0 = -1; s->top1 = MAXSIZE; }
Status Push(sqDoubleStack *s,Elemtype e,int stackNumber){ if(s->top0+1 == s->top1){ return error; } if(stackNumber == 0){ s->data[++s->top0] = e; }else if(satckNumber == 1){ s->data[--s->top1] = e; } return OK; }
Status pop(SqDoubleStack *s,ElemType *e, int stackNumber){ if(stackNumber == 0){ if(s->top0 == -1){ return error; } *e = s->data[s->top0--]; }else if(stackNumber == 1){ if(s->top1 == MAXSIZE){ return error; } *e = s->data[s->top1++]; } return OK; }
|
四、栈的链式存储结构
1、链栈
采用链表的存储的栈为链栈,链表的优点是便于多个栈共享存储空间和提高其效率,且不存在栈满上溢的情况。通常采用单链表实现,并规定所有的操作都是在单链表的表头进行的。这里规定链栈没有头节点,Lhead指向栈顶元素,如图所示。

当栈空的时候,即栈顶没有元素,所以头指针指向空,就是top = NULL的时候
链栈结构代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| #include<stdio.h> #include<stdlib.h> #define MAXSIZE 50 typedef int ElemType;
typedef struct StackNode{ ElemType data; struct StackNode *next; }StackNode,*LinkStackPrt;
typedef struct LinkStack{ LinkStackPrt top; int count; }LinkStack;
|
2、链表的基本算法
(1)链表的进栈

用代码实现,如下:
1 2 3 4 5 6 7 8 9
| Status Push(LinkStack *s,ElemType e){ LinkStackPrt p = (LinkStackPrt)malloc(sizeof(StackNode)); p->data = e; p->next = s->top; s->top = p; s->count++; return OK; }
|
同理,出栈:

1 2 3 4 5 6 7 8 9 10 11 12 13
| Status pop(LinkStack *s,ElemType *e){ LinkStackPtr p; if(StackEmpty(*s)){ return error; } *e = s->top->data; p = s->top; s->top = s->top->next; free(p); s->count--; return OK; }
|
五、栈的应用