二十一.栈和队列的定义和特点
- 栈
- 栈的定义
- 栈是一个特殊的线性表,是限定仅在一段(通常是表尾)进行插入和删除操作的线性表
- 又叫后进后出段的线性表,LIFO结构
- 栈的概念
- 栈是仅在表尾进行插入,删除操作的线性表
- 表尾叫栈顶Top;表头叫栈顶Base
- 入栈
- 插入元素到栈顶(表尾)的操作
- 出栈(弹栈)
- 从标顶(表尾)删除最后一个元素的操作
- 栈的应用
- 栈的定义
- 操作案例
- 进制转换
- 十进制整数N向其他进制数d(二,八,十六)的转换是计算机实现计算的基本问题
- 括号匹配的检验
- 表达式中允许包含两个括号:圆括号和方括号
- 表达式求值
- 程序设计语言编译中一个最基本的问题,它的实现也需要运用栈
- 算符优先于算法
- 表达式的组成
- 操作数:常数、变量
- 运算符:算术运算符、关系运算符和逻辑运算符
- 界限符:左右括弧和表达式结束符
- 任何一个算术表达式都由操作数、算术运算符和界限符组成
- 舞伴问题
- 构造两个队列
- 依次将队头元素出队配成舞伴
- 某对为空,则另外一队等待这下一舞曲第一个可获得舞伴
- 进制转换
二十二.栈的表示和实现
- 栈的抽象数据类型的类型定义
- InistStack(&S) 初始化操作
- 操作结果:构造一个空栈S
-
- DestoryStack(&S) 销毁栈操作
- 初始条件:栈S已存在
- 操作结果:栈S被销毁
-
- StackEmpty(S) 判断S是否为空栈
- 初始条件:栈S已存在
- 操作结果:若栈S为空栈,则返回TRUE,否则FALse
-
- StackLength(S) 求栈的长度
- 初始条件:栈S已存在
- 操作结果:返回S的元素个数,栈的长度
-
- GetTop(S,&e) 取栈顶元素
- 初始条件:栈S已存在且非空
- 操作结果:用e返回S的栈顶元素
-
- ClearStack(&S) 栈置空操作
- 初始条件:栈S已存在
- 操作结果:将S清为空栈
-
- Push(&S,e) 入栈操作
- 初始条件:栈S已存在
- 操作结果:插入元素e为新的栈顶元素
-
- Pop(&S,&e) 出栈操作
- 初始条件:栈S已存在且非空
- 操作结果:删除S的栈顶元素a~n,并用e返回其值
- 栈的表示
- 由于栈本省就是线性表,于是栈也有顺序存储和链式存储两种实现方式
- 栈的顺序存储--顺序栈
- 栈的链式存储--链栈
- 存储方式
- 同一般线性表的顺序存储结构完全相同,利用一组地址连续的存储单元一次存放自栈底到栈顶的数据元素。栈底一般在低地址端
- 附设top指针,指示栈顶元素在顺序栈中的位置
- 另设base指针,指示栈底元素在顺序栈中的位置
- 方便操作,通常top只是真正的栈顶元素之上的下标地址
- 栈空:base==top指针
- 栈满:top-base==stacksize
- 处理方法
- 报错,返回操作系统
- 分配更大空间,将原栈内容移动到新栈
- 处理方法
- stacksize表示栈可使用的最大容量
- 使用数组作为顺序栈存储方式特点
- 简单,方便,但易产生溢出(数组大小固定)
- 上溢:栈已经满,又要压入元素
- 下溢:栈已经空,还要弹出元素
- 注意:上溢是一种错误,问题没有得到处理;下溢一般判定为结束。
- 简单,方便,但易产生溢出(数组大小固定)
- 同一般线性表的顺序存储结构完全相同,利用一组地址连续的存储单元一次存放自栈底到栈顶的数据元素。栈底一般在低地址端
- 由于栈本省就是线性表,于是栈也有顺序存储和链式存储两种实现方式
- 顺序栈的表示
顺序栈的初始化
Status InitStack(SqStack &S) //构建空栈
{S.base=new SElemType[MAXSIZE]; //S.base=(SElemType*)sizeof(SelemType)if(!S.base)exit (OVERFLOW); //存储分配失败S.top=S.base; //栈顶指针等于栈底指针S.stacksize=MAXSIZE;return OK;
}
顺序栈判断栈是否为空
Status StackEmpty(SqStack S)
{if(S.top == S.base)return TRUE;elsereturn FALSE;
}
求顺序栈长度
int StackLength(SqStack S)
{return S.top-S.base;
}
清空顺序栈
Status ClearStack(SqStack S)
{if(S.base)S.top=S.base;return OK;
}
销毁顺序栈
Status DestroyStack(SqStack &S)
{if(S.base){delete S.base;S.stacksize=0;S.base=S.top=NULL;}return OK;
}
- 顺序栈的入栈
- 判断栈是否栈满,若满则出错(上溢)
- 元素e压入栈顶
- 栈顶指针加1
Status Push(SqStack &S,SElemType e)
{if(S.top-S.base==S.stacksize) //栈满return ERROR;*S.top++e;return OK;
}
- 顺序栈的出栈
- 判断是否为空,若空则出错
- 栈顶指针减1
- 获取栈顶元素e
Status Pop(SqStack &S,SElemType &e) //栈不为空,删除s栈顶元素,用e返回值和Ok,否则返回ERROR
{if(S.top==S.base) //等价于if(StackEmpty(S))return ERROR;*S.top++e;return OK;
}
- - 链栈的表示
- - 链栈是运算受限的单链表,只能在链表头部进行操作
- - 链栈的特点
- - 链栈的头指针就是栈顶
- - 不要头结点
- - 基本不存在栈满的情况
- - 空栈相当于头指针指向空
- - 插入和删除仅在栈顶处执行
- - 链栈的特点
- - 链栈是运算受限的单链表,只能在链表头部进行操作
typedef struct StackNode
{SElemType data;struct StackNode *next;
}StackNode,*LinkStack;
LinkStack S;
- 链栈的初始化
void InitStack(LinkStack &S)
{S=NULL;return OK;
}
- 判断链表是否为空
Status StackEmpty(LinkStack S)
{if(S==NULL)return TRUE;else return FALSE;
}
- 链栈的入栈
Status Push(LinkStack &S,SElemType e)
{p=new StackNode //生成新节点pp->data=e; //将新结点数据域为ep->next=S; //将新结点插入栈顶S=p; //修改栈顶指针return OK;
}
- 链栈的出栈
Status Pop(LinkStack &S,SElemType &e)
{if(S==NULL)return ERROR;e=S->data;p=S;S=S->next;delete p;return OK;
}
- 取栈顶元素
SElemType GetTop(LinkStack S)
{if(S!=NULL)return S->data;
}