总结:
- 定义:栈是仅限定在表位进行插入和删除的特殊线性表。
- 共享栈可以节省顺序栈的空间的浪费问题。
- 栈的应用:
- 对一个指定的序列产生不一样的顺序的序列。
- 中缀表达式 转换成 后缀表达式, 以及后缀表达式的计算。
- 函数栈 实现函数调用, 递归函数。
- 链栈 和 顺序栈的比较 : 看最后
栈的定义:
stack是仅限定在表尾 进行 插入 和 删除操作的线性表
允许插入和删除的一端称为top , 另一端bottom , stack 是 LIFO 结构
Stack 的 ADT:
|
ADT stack Data: 同线性表。元素具有相同的类型,相邻元素具有前驱和后继关系。 Operation: InitStack(*S) : 初始化操作,建立一个空Stack。 DestroyStack(*S) : 若栈存在,则销毁。 ClearStack(*S) : 将栈清空。 StackEmpty(S) : 若栈其为空,则返回true,否则false。 GetTop(S, *e) : 若栈S存在,并且非空, 用e返回S的栈顶元素。 Push(*S, e) : 若栈S存在,则插入新的元素e到栈S中,并成为栈顶元素。 Pop(*S, *e) : 删除栈S中的栈顶元素,并用e返回其值 StackLength(S) : 返回栈S的元素的个数。 endADT |
ADT -> 顺序结构 -> 语言实现(C语言) :
顺序结构实现的栈我们叫做顺序栈
SqStack.h : |
/***************************************************************************** File name: SqStack.h Description: 提供数据结构SqStack的定义 和 操作接口, 默认数据类型int 空栈时候 top 的值为-1 Author: MusaGeek Version: 1.0 Date: 2018-11-25 *****************************************************************************/ #ifndef __SEQSTACK_H #define __SEQSTACK_H #define MAXSIZE 20 #define TRUE 1 #define FALSE 0 typedef int SElemType; /*假设栈里面放的元素类型的是int*/ typedef int BOOL typedef struct { SElemType data[MAXSIZE]; int top; }SqStack; /*接口声明*/ extern BOOL push(SqStack *S, SElemType e); extern BOOL Pop(SqStack *S, SElemType *e) /*.....*/ #endif |
SqStack.c : 只实现了 pop 和 push 两个操作 |
/****************************************************** File name: SqStack.c Description: SqStack 操作的实现 Author: MusaGeek Version: 1.0 Date: 2018-11-25 Function List: InitStack(*S) : 初始化操作,建立一个空Stack。 DestroyStack(*S) : 若栈存在,则销毁。 ClearStack(*S) : 将栈清空。 StackEmpty(S) : 若栈其为空,则返回true,否则false。 GetTop(S, *e) : 若栈S存在,并且非空, 用e返回S的栈顶元素。 Push(*S, e) : 若栈S存在,则插入新的元素e到栈S中,并成为栈顶元素。 Pop(*S, *e) : 删除栈S中的栈顶元素,并用e返回其值 StackLength(S) : 返回栈S的元素的个数。 History: ******************************************************/ #include <stdio.h> #include "SqStack.h" /************************************************* Function: Push Description: 若栈S存在,则插入新的元素e到栈S中,并成为栈顶元素。 1.判断栈满否 , 满返回FALSE 2.top上移动 3.在top位置插入元素 4.返回TRUE Input: S : 指向栈的指针 e : 插入栈顶的元素 Return: BOOL *************************************************/ BOOL push(SqStack *S, SElemType e) { if(MAXSIZE - 1 == S->top) /*栈满*/ { return FALSE; } S->top++; S->data[S->top] = e; return TRUE; } /************************************************* Function: Pop Description: 若栈S存在,则插入新的元素e到栈S中,并成为栈顶元素。 1.判断栈空否 , 空则返回FALSE 2.将top指向的元素赋值给*e 3.top-- 4.返回TRUE Input: S : 指向栈的指针 output: e : 弹出的元素经由e输出 Return: BOOL *************************************************/ BOOL Pop(SqStack *S, SElemType *e) { if(-1 == S->top) { return FALSE; } *e = S->datap[S->top]; S->top--; return TRUE; } /*其余操作省略*/ |
共享栈 :
将两个栈共享一个数组, 增加栈的利用率 , 注意一定要相同的数据类型。
ADT->链式结构->语言实现(C语言):
如图:
栈空清空 : top == NULL
栈满 : 不存在
链栈为空的时候 , top 直接为NULL即可 |
/***************************************************************************** File name: LinkStack.h Description: LinkStack 结构体定义 和 接口声明 Author: MusaGeek Version: 1.0 Date: 2018-11-25 *****************************************************************************/ #ifndef __LINKSTACK_H #define __LINKSTACK_H #define TRUE 1 #define FALSE 0 typedef int BOOL; typedef int SElemType; /*结点结构*/ typedef struct StackNode { SElemType data; StackNode *next; }StackNode,*LinkStackPtr; /*链栈结构*/ typedef struct LinkStack { LinkStackPtr top; int counts }LinkStack; #endif |
|
/****************************************************** File name: LinkStack.c Description: LinkStack 数据结构的操作的实现 Author: MusaGeek Version: 1.0 Date: 2018-11-25 Function List: ******************************************************/ #include <stdio.h> #include <stdlib.h> #include "LinkStack.h" /************************************************* Function: Push Description: 掺入元素e为新的栈顶元素 1.为新元素创建一个node 2.将node放置在链栈头部 3.top指向node 4.链栈的元素个数count + 1 5.返回TRUE Input: S : 指向的链栈指针 e : 插入的元素 Return: BOOL *************************************************/ BOOL Push(LinkStack *S, SElemType e) { LinkStackPtr node = (LinkStack)malloc(sizeof(StackNode)); node->data = e; node->next = S->top; S->top = node; S->count++; return TRUE; } /************************************************* Function: Pop Description: 弹出链栈栈顶的元素 1.检查链栈是否其空 , 即 top == NULL 返回 FALSE 2.将top指向的元素data 通过 e传出 3.将top指针指向栈顶元素的下一个元素 , 释放栈顶元素 4.返回TRUE; Input: S : 指向的链栈指针 e : 插入的元素 Return: BOOL *************************************************/ BOOL Pop(LinkStack *S, SElemType *e) { LinkStackPtr temp = S->top: if(NULL == temp) { return FALSE; } *e = temp->data; S->top = temp->next; free(temp); S->count--; return TRUE; } |
顺序栈 和 链栈的对比;
关键操作时间上开销 : Push , Pop 均为O(1)
内存开销 :
(1) 顺序栈 : 无法确定数组大小 , 可能造成空间的浪费
(2) 链栈 : 每个Node多了一个指针域的开销
选择 :
元素变化不可预料, 范围波动较大选择链栈 , 如果在可控范围选择顺序栈
栈的应用:
1.递归 : 函数自己调用自己。
函数栈的实现 : 外层函数的局部变量 , 参数值 , 返回地址 , 都被压入了函数栈当
中,在内层函数执行完毕后将函数栈里面上一层函数信息弹出即可继续执行。高级语言
不需要程序员自己维护这个栈的。
2. 逆波兰表达式完成四则运算: 如下
逆波兰后缀表达式:
中缀表达式转换成后缀表达式 : 从左到右扫描中缀表达式, 遇见数字直接输出, 遇见 ( 压入 , 遇见四则运算符 若其优先级小于栈顶 符号 , 则输出到 ( 或 栈空为止, 遇见 ) 则输出到栈(为止 , 扫描完毕将栈中元素再输出就完成了 中缀表达式 到 后缀表达式的转换了。
后缀表达式计算 : 遇见数字压栈 , 遇见符号弹出两个运算 根据符号运算完毕后再的压入栈当中即可。