清华 殷人昆C++数据结构课件-第二部分-栈和队列,递归与广义表和树与森林
合集下载
数据结构-栈和队列PPT课件

初始条件:栈 S 已存在且非空。 操作结果:删除 S 的栈顶元素,并用 e 返回其值。
.
15
栈的抽象数据类型定义
StackTraverse(S, visit( )) 初始条件:栈 S 已存在且非空,visit( )为元素的访问
函数。 操作结果:从栈底到栈顶依次对S的每个元素调用函数
visit( ),一旦visit( )失败,则操作失败。 } ADT Stack
.
29
3.1.2.2 栈的静态顺序存储表示
4 弹栈(元素出栈)
Status pop( SqStack S, ElemType *e ) /*弹出栈顶元素*/ { if ( S.top==0 ) return ERROR ; /* 栈空,返回错误标志 */ *e=S.stack_array[S.top] ; S.top-- ; return OK ; }
.
11
3.1.1 栈的基本概念
2 栈的抽象数据类型定义
ADT Stack{ 数据对象:D ={ ai|ai∈ElemSet, i=1,2,…,n,n≥0 } 数据关系:R ={<ai-1, ai>|ai-1,ai∈D, i=2,3,…,n } 基本操作:初始化、进栈、出栈、取栈顶元素等
} ADT Stack
进栈(push) 出栈(pop)
top
an
⋯⋯
ai ⋯⋯
a2
bottom
a1
图3-1 顺序栈示意图
.
6
栈的示意图
入栈
• 特点
• 先进后出(FILO) 出栈 • 后进先出(LIFO)
栈顶 栈顶 栈顶
a3 a2
插入:入栈、进栈、压栈 删除:出栈、弹栈
.
15
栈的抽象数据类型定义
StackTraverse(S, visit( )) 初始条件:栈 S 已存在且非空,visit( )为元素的访问
函数。 操作结果:从栈底到栈顶依次对S的每个元素调用函数
visit( ),一旦visit( )失败,则操作失败。 } ADT Stack
.
29
3.1.2.2 栈的静态顺序存储表示
4 弹栈(元素出栈)
Status pop( SqStack S, ElemType *e ) /*弹出栈顶元素*/ { if ( S.top==0 ) return ERROR ; /* 栈空,返回错误标志 */ *e=S.stack_array[S.top] ; S.top-- ; return OK ; }
.
11
3.1.1 栈的基本概念
2 栈的抽象数据类型定义
ADT Stack{ 数据对象:D ={ ai|ai∈ElemSet, i=1,2,…,n,n≥0 } 数据关系:R ={<ai-1, ai>|ai-1,ai∈D, i=2,3,…,n } 基本操作:初始化、进栈、出栈、取栈顶元素等
} ADT Stack
进栈(push) 出栈(pop)
top
an
⋯⋯
ai ⋯⋯
a2
bottom
a1
图3-1 顺序栈示意图
.
6
栈的示意图
入栈
• 特点
• 先进后出(FILO) 出栈 • 后进先出(LIFO)
栈顶 栈顶 栈顶
a3 a2
插入:入栈、进栈、压栈 删除:出栈、弹栈
数据结构第一章 (清华 殷人昆版)

什么是数据结构 抽象数据类型及面向对象概念 数据结构的抽象层次 C++描述面向对象程序 用C++描述面向对象程序 算法定义 模板 性能分析与度量
作为抽象数据类型的数组 顺序表 稀疏矩阵 字符串
单链表 循环链表 多项式及其相加 双向链表 稀疏矩阵Leabharlann 栈 表达式求值 队列 优先队列
递归的概念 递归过程与递归工作栈 递归与回溯 广义表
�
清华大学计算机系 殷人昆
与国际当前教学内容接轨
基于抽象数据类型 完全实现信息隐蔽 引入简单算法分析 结合结构化程序设计与 面向对象程序设计 已有三轮教学基础 语言流畅,概念清晰
先修课程
C / C++ 程序设计 简单的集合 / 图论知识
主要内容
数据结构概念 数组与顺序表 链表 栈,队列与优先权队列 递归,回溯与广义表 树与森林 集合与搜索 图 排序 索引与散列(文件)
树和森林的概念 二叉树 二叉树遍历 二叉树的计数 线索化二叉树 堆 树与森林 霍夫曼树
集合及其表示 并查集 静态搜索表 二叉搜索树 AVL树 AVL树
图的基本概念 图的存储表示 图的遍历与连通性 最小生成树 最短路径 活动网络
概述 插入排序 交换排序 选择排序 归并排序 基数排序 外排序
静态索引结构 动态索引结构 散列 可扩充散列
附录A 用C++描述面向对象程序 ++描述面向对象程序
用模板定义C++中的类 类中成员函数的实现 函数名重载和操作符重载 C++中的主函数
目前清华大学已有 目前清华大学已有2届学生使用 清华大学 过此教材, 过此教材, 人数达 350 人; 中 专升本在学人 央广播电视大学专升本 央广播电视大学专升本在学人 数 8000 人.
递归--清华大学课程讲义-数据结构(PPT)

2013-9-10 2
递归算法举例——迷宫问题递归算法
void RecurveSeek ( int i , j ) //进入时 ( i , j )是一通道块,尚未印足迹,不在当前路径上。本函数 //从 ( i , j ) 起探索并输出以此时当前路径为前缀的所有成功的简单路 //径,退出时状态同进入时状态 { maze[ i ] [ j ] = ‘0’ ; //印足迹,归入当前路径 if ( i == n && j == n ) printmaze( ) ; //简单情况 else for ( k = 0 ; k < 4 ; k ++ ) //试探东南西北四个方向 if ( maze[ i + di[ k ] ] [ j + dj[ k ] ] == ‘ ‘ ) //若下一块是通道 RecurveSeek( i + di[ k ] , j + dj[ k ] ) ; //则递归调用 maze[ i , j ] = ‘ ‘ ; //回溯,恢复进入时状态 }
第5章
递归(Recurve)
定义: 若一个对象部分地包含它自己,或用它自己给自己定义,则 称这个对象是递归的;而且一个过程直接地或间接地调用自 己,则称这个过程是递归的过程。 应用: (1)用于某些概念的定义: 阶乘: if ( n>0 ) n ! = n ( n-1 ) ! if ( n=0 ) n ! = 1 单链表结点: template <class Type> class ListNode {private: Type data; ListNode<Type> * Link; } 二叉树:二叉树是数据元素的有穷集合,它或者为空集(空 二叉树),或者由一个根元素和其下的两棵互不相 交的二叉树(左子树和右子树)构成。
递归算法举例——迷宫问题递归算法
void RecurveSeek ( int i , j ) //进入时 ( i , j )是一通道块,尚未印足迹,不在当前路径上。本函数 //从 ( i , j ) 起探索并输出以此时当前路径为前缀的所有成功的简单路 //径,退出时状态同进入时状态 { maze[ i ] [ j ] = ‘0’ ; //印足迹,归入当前路径 if ( i == n && j == n ) printmaze( ) ; //简单情况 else for ( k = 0 ; k < 4 ; k ++ ) //试探东南西北四个方向 if ( maze[ i + di[ k ] ] [ j + dj[ k ] ] == ‘ ‘ ) //若下一块是通道 RecurveSeek( i + di[ k ] , j + dj[ k ] ) ; //则递归调用 maze[ i , j ] = ‘ ‘ ; //回溯,恢复进入时状态 }
第5章
递归(Recurve)
定义: 若一个对象部分地包含它自己,或用它自己给自己定义,则 称这个对象是递归的;而且一个过程直接地或间接地调用自 己,则称这个过程是递归的过程。 应用: (1)用于某些概念的定义: 阶乘: if ( n>0 ) n ! = n ( n-1 ) ! if ( n=0 ) n ! = 1 单链表结点: template <class Type> class ListNode {private: Type data; ListNode<Type> * Link; } 二叉树:二叉树是数据元素的有穷集合,它或者为空集(空 二叉树),或者由一个根元素和其下的两棵互不相 交的二叉树(左子树和右子树)构成。
数据结构与程序设计课件-栈与队

例 在一个初始为空的链接栈中依次插入元素 A, B, C, D 以后, 栈的状态为
top
D
C
B
A^
栈顶元素
链栈是一种特殊的链表,其结点的插入(进栈)和删 除(出栈)操作始终在链表的头。
struct node { SElmeType data; struct node *link;
}; typedef struct node *Nodeptr; typedef struct node Node; Nodeptr Top; //即为链表的头结点指针
a+b*c+(d*e+f)/g
后缀表达式的最大好处是 没有括号,也不用考虑运
算符的优先级!
在(计算机)计算表达式的值时面临的主要问题有: 运算符有优先级 括号会改变计算的次序
为了方便表达式的(计算机)计算,波兰数学家Lukasiewicz在20 世纪50年代发明了一种将运算符写在操作数之后的表达式表示方
012 …
第1个栈
M-1
第2个栈
top1 top2
栈满的条件是 top1==top2–1
栈满
算法
void push( ElemType s[ ], int i, ElemType item )
{
if(top1==top2–1)
/* 栈满 */
Error(“Full Stack!”);
else{
if(i==1)
后进先出
栈(Stack) 是一种只允许在表的一端进行插入操
作和删除操作的线性表。允许操作的一端称为栈 顶,栈顶元素的位置由一个称为栈顶位置的变量 给出。当表中没有元素时,称之为空栈。
abcdex
top
数据结构C语言版ppt课件-PPT精品文档

…
an-1,0 an-1,1
…
an-1,n-1
an-1,0 an-1,1
…
…
Ann
a0,0 a1,0
a0,1 a1,1
… …
a0,n-1 a1,n-1
Ann
a0,0 a1,0
a1,1
…
…
…
an-1,n-1
对称阵
中国网页设计 xin126
下三角矩阵
第5章 数组和广义表
中国网页设计 xin126
数据结构
(C语言版)
严蔚敏、吴伟民编著 清华大学出版社 学习网站:xin126/list.asp?id=301
中国网页设计 xin126
第5章 数组和广义表
主要内容:
一、数组的定义 二、数组的表示和实现 三、矩阵的压缩存储 四、广义表的定义 五、广义表的存储结构
中国网页设计 xin126
第5章 数组和广义表
0 0 0 0 0 0
0 0 0 0 0 0
中国网页设计 xin126
第5章 数组和广义表
(2) 稀疏矩阵的存储: 若按常规方法进行存储,零值元素会占了很大空间 因此对于稀疏矩阵的存储通常采用以下两种方式: 三元组表和十字链表进行存储。
中国网页设计 xin126
第5章 数组和广义表
中国网页设计 xin126
第5章 数组和广义表
以行序为主序的求址公式:
假设每个数据元素占L个存储单元,则二维 数组A中任一元素aij的存储位置可由下式确定: LOC(i, j) = LOC(0, 0) + (n×i + j)*L 式中,LOC(i, j)是aij的存储位置,LOC(0, 0)是a00的存储位置,即二维数组A的起始存储 位置,也称为基地址或基址。b2是数组第二维 的长度,即数组A(m×n)中的列数n。
数据结构3(清华大学)ppt

//判集合this与R相等
friend istream& operator >> (istream& in,
bitSet<T>& R);
//输入
friend ostream& operator << (ostream& out,
bitSet<T>& R);
//输出
private:
int setSize;
bitVector = new int [vectorSize]; //分配空间
assert (bitVector != NULL); //检查存储分配是否成功
for (int i = 0; i < vectorSize; i++) //初始化
bitVector[i] = R.bitVector[i];
//集合大小
int vecterSize;
//位数组大小
unsigned short *bitVector;
//存储集合元素的位数组
};
11
使用示例
Set s1, s2, s3, s4, s5; int index, equal; for (int k = 0; k < 10; k++) { //集合赋值
清华大学计算机系 数据结构(用面向对象方法与
C++语言描述)第二版3
殷人昆
1
数据结构电子教案
第六章 集合与字典
殷人昆 王 宏
2
第六章 集合与字典
• 集合及其表示 • 并查集与等价类 • 字典 • 跳表 • 散列
3
集合及其表示
清华大学殷仁昆教授数据结构C语言描述PPT课件

第2页/共18页
数据结构课程的地位
• 是介于数学、计算机硬件和计算机软件三 者之间的一门核心课程数据结构课程的地 位。
关系
数学
对象
对象
关系
软件
硬件
关系
操作
操作
第3页/共18页
• 数据结构是一门研究非数值计算的程序设 计问题中计算机的操作对象及其之间关系 与操作的学科。是介于数学、计算机硬件 和计算机软件三者之间的一门核心课程, 属于计算机学科中的一门综合性专业基础 课程。
第5页/共18页
选修课课程设置与数据结构的关系
数据结构基础
计算机科学基础
算法与数 据结构Ⅱ
文件处理 (数据库)
算法设计与分析
软件工程
系统模拟
图形学
第6页/共18页
数值计算解决问题的一般步骤:
• 数学模型→选择计算机语言→编出程序 →测试→最终解答。
• 数值计算的关键是:如何得出数学模型 (方程)?
第8页/共18页
求解非数值计算的问题的步骤:
• 主要考虑的是设计出合适的数据结构及相 应的算法。即首先要考虑对相关的各种信 息如何表示、组织和存储?
• 可以认为:数据结构是一门研究非数值计 算的程序设计问题中计算机的操作对象以 及它们之间的关系和操作的学科。
第9页/共18页
数据结构课程的特点
• 数据结构课程是计算机专业基础课,主 要训练学生在系统开发中的数据设计、 算法设计与分析及数据组织的能力,它 是后续多门课程,如数据库、操作系统、 编译原理、网络系统基础等的基础,对 于从事计算机系统开发的人员,是必修 课程之一。
• 自觉预习、遵守纪律、认真听课、及时复 习;
• 按时、独立、认真地完成每次作业; • 完成作业方式:
数据结构课程的地位
• 是介于数学、计算机硬件和计算机软件三 者之间的一门核心课程数据结构课程的地 位。
关系
数学
对象
对象
关系
软件
硬件
关系
操作
操作
第3页/共18页
• 数据结构是一门研究非数值计算的程序设 计问题中计算机的操作对象及其之间关系 与操作的学科。是介于数学、计算机硬件 和计算机软件三者之间的一门核心课程, 属于计算机学科中的一门综合性专业基础 课程。
第5页/共18页
选修课课程设置与数据结构的关系
数据结构基础
计算机科学基础
算法与数 据结构Ⅱ
文件处理 (数据库)
算法设计与分析
软件工程
系统模拟
图形学
第6页/共18页
数值计算解决问题的一般步骤:
• 数学模型→选择计算机语言→编出程序 →测试→最终解答。
• 数值计算的关键是:如何得出数学模型 (方程)?
第8页/共18页
求解非数值计算的问题的步骤:
• 主要考虑的是设计出合适的数据结构及相 应的算法。即首先要考虑对相关的各种信 息如何表示、组织和存储?
• 可以认为:数据结构是一门研究非数值计 算的程序设计问题中计算机的操作对象以 及它们之间的关系和操作的学科。
第9页/共18页
数据结构课程的特点
• 数据结构课程是计算机专业基础课,主 要训练学生在系统开发中的数据设计、 算法设计与分析及数据组织的能力,它 是后续多门课程,如数据库、操作系统、 编译原理、网络系统基础等的基础,对 于从事计算机系统开发的人员,是必修 课程之一。
• 自觉预习、遵守纪律、认真听课、及时复 习;
• 按时、独立、认真地完成每次作业; • 完成作业方式:
《栈和队列梁》课件

对比分析
总结词
各有优缺点
详细描述
数组实现和链表实现各有优缺点。数组实现具有简单直观的优点,但在实际应用中可能会受到数组大 小限制的影响。链表实现更加灵活,但需要注意指针操作和内存管ห้องสมุดไป่ตู้问题。具体选择哪种实现方式需 要根据实际需求和应用场景来决定。
05
栈和队列的常见问题与解 决方案
栈溢出问题
栈溢出问题
当栈的大小不足以容纳新元素时 ,会发生栈溢出。这通常是由于 递归深度过深或栈空间分配不足
导致的。
解决方案
为栈分配足够的空间,避免过深的 递归,或者使用循环代替递归。
优化建议
使用动态内存分配函数(如malloc 和free)来动态调整栈的大小,以 适应不同的情况。
队列空指针问题
队列空指针问题
优化建议
栈的特性
先进后出(FILO)
栈中的元素必须遵循后进先出的原则,即最后一个进入栈的元素 将是第一个出去的元素。
插入和删除操作在栈顶进行
栈只允许在固定的一端(称为栈顶)进行插入和删除操作。
动态性
栈的大小可以根据需要进行动态调整。
栈的应用场景
后进先出(LIFO)的场景
01
如括号匹配、函数调用堆栈等,需要最后进入的元素最先出来
队列主要有入队、出队 、查看队首元素等操作
。
队列的应用场景
01
02
03
任务调度
在多任务系统中,可以使 用队列来实现任务的调度 和管理。
缓冲处理
在输入输出系统中,可以 使用队列来缓存数据,实 现数据的缓冲处理。
事件处理
在事件驱动的系统中,可 以使用队列来管理事件, 实现事件的顺序处理和并 发处理。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
<操作符> <操作数> <操作数>,如 +AB;
后缀(postfix)表示
<操作数> <操作数> <操作符>,如 AB+;
表达式的中缀表示
a+b*(c-d)-e^f/g
rst1 rst2 rst3
rst4 rst5
rst6
表达式中相邻两个操作符的计算次序为: 优先级高的先计算; 优先级相同的自左向右计算; 当使用括号时从最内层括号开始计算。
链式栈 (LinkedStack)类的定义
template <class Type> class Stack;
template <class Type> class StackNode {
friend class Stack<Type>;
private:
Type data;
//结点数据
StackNode<Type> *link; //结点链指针
}
中缀算术表达式求值
使用两个栈,操作符栈OPTR (operator), 操作数栈OPND(operand),
栈 表达式求值 队列 优先队列
栈 ( Stack )
只允许在一端插入和删除的线性表
允许插入和删除 退栈 进栈
的一端称为栈顶 (top),另一端称 为栈底(bottom) 特点 后进先出 (LIFO)
top
an-1
an-2
a0 bottom
栈的抽象数据类型
template <class Type> class Stack {
elements = new Type[maxSize]; assert ( elements != NULL ); //断言
}
top 空栈
top e d c b a
e 进栈
top a a 进栈
top b a
b 进栈
top e
d
top
c
b a
f 进栈溢出
e d c b a
e 退栈
d top c
b a d 退栈
template <class Type> void Stack<Type> :: Push ( const Type &item ) {
top = new StackNode<Type> ( item, top ); //新结点链入*top之前, 并成为新栈顶 }
template <class Type> int Stack<Type> ::
14 + 操作符 r5、r3 退栈, 计算 r6 r3+r5, 结果 r6 进栈
void Calculator :: Run ( ) {
char ch; double newoperand;
while ( cin >> ch, ch != ‘=’ ) {
switch ( ch ) { case ‘+’ : case ‘-’ : case ‘*’ : case ‘/’ :
步 输入 类 型
动作
栈内容
1
置空栈
空
2 A 操作数 进栈
A
3 B 操作数 进栈
AB
4 C 操作数 进栈
ABC
5 D 操作数 进栈
ABCD
6 - 操作符 D、C 退栈, 计算 ABr1
C-D, 结果 r1 进栈
7 * 操作符 r1、B 退栈, 计算 Ar2
B*r1, 结果 r2 进栈
8 + 操作符 r2、A 退栈, 计算 r3
DoOperator ( ch ); break; //计算
default : cin.putback ( ch ); //将字符放回输入流
cin >> newoperand; //读操作数
AddOperand ( newoperand );
}
}
}
利用栈将中缀表示转换为后缀表示
使用栈可将表达式的中缀表示转换成它 的前缀表示和后缀表示。
配对或栈底的“;”号与输入流最后的“;” 号配对时。
中缀表达式转换为后缀表达式的算法
操作符栈初始化,将结束符‘;’进栈。然 后读入中缀表达式字符流的首字符ch。
重复执行以下步骤,直到ch = ‘;’,同时 栈顶的操作符也是‘;’,停止循环。 若ch是操作数直接输出,读入下一个 字符ch。 若ch是操作符,判断ch的优先级icp和 位于栈顶的操作符op的优先级isp:
int IsEmpty ( ) { return top == NULL; }
}
template <class Type> Stack<Type> :: ~Stack ( ) {
StackNode<Type> *p; while ( top != NULL ) //逐结点回收
{ p = top; top = top->link; delete p; } }
assert ( !IsEmpty ( ) ); return top->data;
}
表达式求值
一个表达式由操作数(亦称运算对象)、操 作符 (亦称运算符) 和分界符组成。
算术表达式有三种表示: 中缀(infix)表示
<操作数> <操作符> <操作数>,如 A+B;
前缀(prefix)表示
rst1
rst4
rst2
rst5
rst3
rst6
通过后缀表示计算表达式值的过程
顺序扫描表达式的每一项,根据它的类 型做如下相应操作: 若该项是操作数,则将其压栈; 若该项是操作符<op>,则连续从栈中 退出两个操作数Y和X,形成运算指令 X<op>Y,并将计算结果重新压栈。
当表达式的所有项都扫描并处理完后, 栈顶存放的就是最后的计算结果。
C++中操作符的优先级
优先级 操作符
1
单目-、!
2
*、/、%
3
+、-
4 <、<=、>、>=
5
==、!=
6
&&
7
||
一般表达式的操作符有4种类型:
1 算术操作符 如双目操作符(+、-、 *、/ 和%)以及单目操作符(-)。
2 关系操作符 包括<、<=、==、!=、 >=、>。这些操作符主要用于比较。
Pop ( ) {
if ( IsEmpty ( ) ) return 0;
StackNode<Type> *p = top;
top = top->link;
//修改栈顶指针
delete p; return 1; //释放
}
template <class Type> Type Stack<Type>:: GetTop ( ) {
stack<char> s; char ch, op;
s.Push ( ‘;’ ); cin.Get ( ch );
while ( ! s.IsEmpty( ) && ch != ';' ) if ( isdigit ( ch ) ) { cout << ch; cin.Get ( ch ); } else { if ( isp ( s.GetTop( ) ) < icp ( ch ) ) { s.Push ( ch ); cin.Get ( ch ); } else if ( isp ( s.GetTop( ) ) > icp ( ch ) ) { op = s.GetTop ( ); s.Pop( ); cout << op; } else { op = s.GetTop ( ); s.Pop( ); if ( op == ‘(’ ) cin.Get ( ch ); } }
A+r2, 结果 r3 进栈
r3E
10 F 操作数 进栈
r3EF
11 ^ 操作符 F、E 退栈, 计算 r3r4 E^F, 结果 r4 进栈
12 G 操作数 进栈
r3r4G
13 / 操作符 G、r4 退栈, 计算 r3r5 r4/E, 结果 r5 进栈
GetTop ( ) { assert ( !IsEmpty ( ) ); //先决条件断言 return elements[top]; //取出栈顶元素
}
双栈共享一个栈空间
0
V
maxSize-1
b[0]
t[0] t[1]
b[1]
栈的链接表示 — 链式栈
top
链式栈无栈满问题,空间可扩充 插入与删除仅在栈顶处执行 链式栈的栈顶在链头 适合于多栈操作
int IsEmpty ( ) const { return top == -1; }
int IsFull ( ) const
{ return top == maxSize-1; }
}
template <class Type> Stack<Type> :: Stack ( int s ) : top (-1), maxSize (s) {
c top b
a
c 退栈
b top a
b 退栈
a top a 退栈
top 空栈
template <class Type> void Stack<Type> ::
Push ( Type & item ) {
后缀(postfix)表示
<操作数> <操作数> <操作符>,如 AB+;
表达式的中缀表示
a+b*(c-d)-e^f/g
rst1 rst2 rst3
rst4 rst5
rst6
表达式中相邻两个操作符的计算次序为: 优先级高的先计算; 优先级相同的自左向右计算; 当使用括号时从最内层括号开始计算。
链式栈 (LinkedStack)类的定义
template <class Type> class Stack;
template <class Type> class StackNode {
friend class Stack<Type>;
private:
Type data;
//结点数据
StackNode<Type> *link; //结点链指针
}
中缀算术表达式求值
使用两个栈,操作符栈OPTR (operator), 操作数栈OPND(operand),
栈 表达式求值 队列 优先队列
栈 ( Stack )
只允许在一端插入和删除的线性表
允许插入和删除 退栈 进栈
的一端称为栈顶 (top),另一端称 为栈底(bottom) 特点 后进先出 (LIFO)
top
an-1
an-2
a0 bottom
栈的抽象数据类型
template <class Type> class Stack {
elements = new Type[maxSize]; assert ( elements != NULL ); //断言
}
top 空栈
top e d c b a
e 进栈
top a a 进栈
top b a
b 进栈
top e
d
top
c
b a
f 进栈溢出
e d c b a
e 退栈
d top c
b a d 退栈
template <class Type> void Stack<Type> :: Push ( const Type &item ) {
top = new StackNode<Type> ( item, top ); //新结点链入*top之前, 并成为新栈顶 }
template <class Type> int Stack<Type> ::
14 + 操作符 r5、r3 退栈, 计算 r6 r3+r5, 结果 r6 进栈
void Calculator :: Run ( ) {
char ch; double newoperand;
while ( cin >> ch, ch != ‘=’ ) {
switch ( ch ) { case ‘+’ : case ‘-’ : case ‘*’ : case ‘/’ :
步 输入 类 型
动作
栈内容
1
置空栈
空
2 A 操作数 进栈
A
3 B 操作数 进栈
AB
4 C 操作数 进栈
ABC
5 D 操作数 进栈
ABCD
6 - 操作符 D、C 退栈, 计算 ABr1
C-D, 结果 r1 进栈
7 * 操作符 r1、B 退栈, 计算 Ar2
B*r1, 结果 r2 进栈
8 + 操作符 r2、A 退栈, 计算 r3
DoOperator ( ch ); break; //计算
default : cin.putback ( ch ); //将字符放回输入流
cin >> newoperand; //读操作数
AddOperand ( newoperand );
}
}
}
利用栈将中缀表示转换为后缀表示
使用栈可将表达式的中缀表示转换成它 的前缀表示和后缀表示。
配对或栈底的“;”号与输入流最后的“;” 号配对时。
中缀表达式转换为后缀表达式的算法
操作符栈初始化,将结束符‘;’进栈。然 后读入中缀表达式字符流的首字符ch。
重复执行以下步骤,直到ch = ‘;’,同时 栈顶的操作符也是‘;’,停止循环。 若ch是操作数直接输出,读入下一个 字符ch。 若ch是操作符,判断ch的优先级icp和 位于栈顶的操作符op的优先级isp:
int IsEmpty ( ) { return top == NULL; }
}
template <class Type> Stack<Type> :: ~Stack ( ) {
StackNode<Type> *p; while ( top != NULL ) //逐结点回收
{ p = top; top = top->link; delete p; } }
assert ( !IsEmpty ( ) ); return top->data;
}
表达式求值
一个表达式由操作数(亦称运算对象)、操 作符 (亦称运算符) 和分界符组成。
算术表达式有三种表示: 中缀(infix)表示
<操作数> <操作符> <操作数>,如 A+B;
前缀(prefix)表示
rst1
rst4
rst2
rst5
rst3
rst6
通过后缀表示计算表达式值的过程
顺序扫描表达式的每一项,根据它的类 型做如下相应操作: 若该项是操作数,则将其压栈; 若该项是操作符<op>,则连续从栈中 退出两个操作数Y和X,形成运算指令 X<op>Y,并将计算结果重新压栈。
当表达式的所有项都扫描并处理完后, 栈顶存放的就是最后的计算结果。
C++中操作符的优先级
优先级 操作符
1
单目-、!
2
*、/、%
3
+、-
4 <、<=、>、>=
5
==、!=
6
&&
7
||
一般表达式的操作符有4种类型:
1 算术操作符 如双目操作符(+、-、 *、/ 和%)以及单目操作符(-)。
2 关系操作符 包括<、<=、==、!=、 >=、>。这些操作符主要用于比较。
Pop ( ) {
if ( IsEmpty ( ) ) return 0;
StackNode<Type> *p = top;
top = top->link;
//修改栈顶指针
delete p; return 1; //释放
}
template <class Type> Type Stack<Type>:: GetTop ( ) {
stack<char> s; char ch, op;
s.Push ( ‘;’ ); cin.Get ( ch );
while ( ! s.IsEmpty( ) && ch != ';' ) if ( isdigit ( ch ) ) { cout << ch; cin.Get ( ch ); } else { if ( isp ( s.GetTop( ) ) < icp ( ch ) ) { s.Push ( ch ); cin.Get ( ch ); } else if ( isp ( s.GetTop( ) ) > icp ( ch ) ) { op = s.GetTop ( ); s.Pop( ); cout << op; } else { op = s.GetTop ( ); s.Pop( ); if ( op == ‘(’ ) cin.Get ( ch ); } }
A+r2, 结果 r3 进栈
r3E
10 F 操作数 进栈
r3EF
11 ^ 操作符 F、E 退栈, 计算 r3r4 E^F, 结果 r4 进栈
12 G 操作数 进栈
r3r4G
13 / 操作符 G、r4 退栈, 计算 r3r5 r4/E, 结果 r5 进栈
GetTop ( ) { assert ( !IsEmpty ( ) ); //先决条件断言 return elements[top]; //取出栈顶元素
}
双栈共享一个栈空间
0
V
maxSize-1
b[0]
t[0] t[1]
b[1]
栈的链接表示 — 链式栈
top
链式栈无栈满问题,空间可扩充 插入与删除仅在栈顶处执行 链式栈的栈顶在链头 适合于多栈操作
int IsEmpty ( ) const { return top == -1; }
int IsFull ( ) const
{ return top == maxSize-1; }
}
template <class Type> Stack<Type> :: Stack ( int s ) : top (-1), maxSize (s) {
c top b
a
c 退栈
b top a
b 退栈
a top a 退栈
top 空栈
template <class Type> void Stack<Type> ::
Push ( Type & item ) {