本 章 说 明 3.1 栈 3.2 栈的应用举例 3.3 栈与递归的实现 3.4 队 列 本 章 小 结 返回主目录.

Slides:



Advertisements
Similar presentations
一、算法的基本概念 二、数据结构 三、栈和队列 四、排序方法 五、二叉树
Advertisements

计算学科的基本问题 本章首先介绍一个对问题进行抽象的典型实例——哥尼斯堡七桥问题。然后,通过“梵天塔”问题和“停机问题”分别介绍学科中的可计算问题和不可计算问题。从“梵天塔”问题再引出算法复杂性中的难解性问题、P类问题和NP类问题,证比求易算法,P=NP是否成立的问题。
问题的提出: 例1 把十进制整数转换为二至十六之间的任一进制数输出。
实用数据结构基础 第3章 栈.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
第三章 堆疊與佇列的基本應用 3-1 簡介堆疊(Stack) 3-2 迷宮問題研究 3-3 佇列(queue)的介紹
第3章 栈和队列.
主要内容: 1.第一部分 概述 2.第二部分 线性表、栈、队列
第三章栈和队列 栈 队列 递归.
資料結構簡介.
数据结构.
Chap 3 堆疊與佇列 Stack and Queue.
强连通分量 无向图 1、任意两顶点连通称该图为连通图 2、否则将其中的极大连通子图称为连通分量 A D C B E 有向图
第3章 顺序存储结构的表、堆栈和队列 3.1 顺序存储结构 3.2 表和顺序表 3.3 堆栈和顺序堆栈 3.4 队列和顺序队列
Ch.3 栈和队列 黄刘生 中国科学技术大学计算机系 国家高性能计算中心(合肥)
线性表小结 元素之间的线性关系 顺序表 顺序表:元素相邻存储 单链表:后继指针链接 一维数组 给定下标随机存取
cn/~dongeliu/dsa.html 刘 东 信息学院6系 中国科学技术大学
第3章 栈和队列(二) 1/.
第三章 栈和队列 栈和队列是两种重要的数据结构。
第3章 栈和队列 丽水学院工学院.
1、栈及其实现 2、栈的应用 3、队列及其实现 4、优先级队列 5、链式队列 6、队列应用
第5章 堆疊(Stacks) 5-1 堆疊的基礎 5-2 堆疊的表示法 5-3 堆疊的應用 - 運算式的計算與轉換
第5章 堆疊(Stacks) 5-1 堆疊的基礎 5-2 堆疊的表示法 5-3 堆疊的應用 - 運算式的計算與轉換
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
第3章 堆栈和队列 堆栈 堆栈应用 队列 队列应用 优先级队列 主要知识点.
第三章 栈与队列 £3.1 栈 £3.3 队列 £3.2 栈的应用举例 £3.1.1 栈的定义 £3.1.2 栈的顺序存储结构
指针与引用 概念 指针从本质上讲就是存放变量地址 的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变。 引用是一个别名,它在逻辑上不是独立的,它 的存在具有依附性,所以引用必须在一开始就被初始化,而且其引用的对象在其整个生命周期中是不能被改变的(自始至终只能依附于同一个变量)。
第三章 栈和队列 3.1 栈 3.2 栈的应用举例 3.3 栈与递归的实现 3.4 队列.
第3章 栈和队列(一).
第三章 栈和队列.
第六讲栈和队列(一)增加 1/13.
数据结构 Data Structure 中南大学 主讲人:王国军,郑瑾 中南大学信息院计科系
第五讲 四则运算计算器(一) 精品教程《C#程序设计与应用(第2版)清华大学出版社 谭恒松 主编
第一章 绪论.
陈海明 副教授 信息学院 计算机系 电子信息类非计算机专业选修课 程序设计实践 陈海明 副教授 信息学院 计算机系
教 师:曾晓东 电 话: E_mail: 计算机软件技术基础 教 师:曾晓东 电 话: E_mail:
第3章 栈和队列 3.1 栈 本章主题:栈和队列的应用 教学目的:掌握栈和队列的应用方法,理解栈的重要作用
第3章 栈与队列.
数 据 结 构 刘家芬 Sept 2012.
第二章 Java语言基础.
动态规划(Dynamic Programming)
第三章 栈和队列.
第3章 栈和队列 ——操作受限的线性表 3.1 栈 3.1.1抽象数据类型栈的定义 3.1.2栈的表示与实现
严蔚敏、吴伟民编著 清华大学出版社 学习网站:
数据结构概论 第3章 栈和队列 董黎刚 浙江工商大学信电学院 2019年2月25日.
第四章 栈和队列 4.1栈 4.2栈的应用 4.3队列 4.3队列应用.
计算机软件技术基础 数据结构与算法(3).
第三章 栈和队列 第二部分 队列(Queue) 2019/4/8.
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
简单介绍 用C++实现简单的模板数据结构 ArrayList(数组, 类似std::vector)
$9 泛型基础.
顺序表的删除.
11.1 递归的定义 11.2 常见递归问题 11.3 递归的实现 11.4 递归转化为非递归的一般过程 11.5 递归的时间和空间复杂度
队列及其实现.
C语言程序设计 第一章 数据类型, 运算符与表达式 第二章 顺序程序设计 第三章 选择结构程序设计 第四章 循环控制 第五章 数组.
第 四 讲 线性表(二).
第4章 Excel电子表格制作软件 4.4 函数(一).
第九节 赋值运算符和赋值表达式.
§6.7 子空间的直和 一、直和的定义 二、直和的判定 三、多个子空间的直和.
3.16 枚举算法及其程序实现 ——数组的作用.
第 六 讲 栈和队列(一).
本章的基本内容是: ⑴栈和队列的定义及操作特性; 第3章 特殊线性表—栈、队列和串 ⑵栈和队列的两种存储方法和基本运算的实现;
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
实验目的:掌握数据的顺序存储结构及它们在计算机中的操作。 实验内容:
第七讲 栈和队列(二) 1/.
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
第3章 栈和队列 3.1 栈 3.2 队列.
第三章 栈和队列.
昆山爱达人信息技术有限公司 QQ: 本节内容 1.栈的链式存储结构及实现 2.栈的应用.
Presentation transcript:

本 章 说 明 3.1 栈 3.2 栈的应用举例 3.3 栈与递归的实现 3.4 队 列 本 章 小 结 返回主目录

本章说明 学习目标 掌握栈和队列这两种抽象数据类型的特点,并能在相应的应用问题中正确选用它们 熟练掌握栈类型的两种实现方法 熟练掌握循环队列和链队列的基本操作实现算法 理解递归算法执行过程中栈的状态变化过程。 重点和难点 掌握栈和队列这两种结构的特点,以便能在应用问题中正确使用 知识点 顺序栈、链栈、循环队列、链队列

栈和队列是在程序设计中被广泛使用的两种线性数据结构,它们的特点在于基本操作的特殊性,栈必须按“后进先出”的规则进行操作,而队列必须按“先进先出”的规则进行操作。和线性表相比,它们的插入和删除操作受更多的约束和限定,故又称为限定性的线性表结构。线性表和栈及队列的插入和删除操作的主要区别: 线性表允许在表内任一位置进行插入和删除 栈只允许在表尾一端进行插入和删除 队列只允许在表尾一端进行插入,在表头一端进行删除

定义:限定仅在表尾进行插入或删除操作的线性表,表尾—栈顶,表头—栈底,不含元素的空表称空栈 特点:先进后出(FILO)或后进先出(LIFO) 3.1  栈 1.栈的定义和特点 定义:限定仅在表尾进行插入或删除操作的线性表,表尾—栈顶,表头—栈底,不含元素的空表称空栈 特点:先进后出(FILO)或后进先出(LIFO) 基本操作: 插入 删除 初始化 取栈顶元素 判空等 an a1 a2 ……... 栈底 栈顶 ... 出栈 进栈 栈s=(a1,a2,……,an)

数据对象:D={ ai| ai∈ElemSet, i=1, …, n, n>=0} 3.1  栈 2.栈的抽象数据类型定义 ADT Stack{ 数据对象:D={ ai| ai∈ElemSet, i=1, …, n, n>=0} 数据关系:R1={<ai-1, ai>|ai-1, ai∈D, i=2 ,…, n } 基本操作: InitStack(&S) //建空栈 DestroyStack(&S) //撤消栈 ClearStack(&S) //清空栈

StackLength(S) //返回栈元素个数 GetTop(S, &e) //用e返回栈顶元素 3.1  栈 StackEmpty(&S) //判空栈 StackLength(S) //返回栈元素个数 GetTop(S, &e) //用e返回栈顶元素 Push(&S, e) //在栈顶插入元素e Pop(&S, &e) //在栈顶删除元素,e返 StackTraverse(S,visit()) }ADT Stack

top=base,栈空,此时出栈,则下溢(underflow) top=M,栈满,此时入栈,则上溢(overflow) 3.1  栈 3.栈的表示和实现 (1)栈的存储结构 顺序栈 实现:一维数组s[M] 栈空 栈满 top top top 1 2 3 4 5 A B C D E F top=0 1 2 3 4 5 栈空 top 1 2 3 4 5 F top top E top top D top top C top top B top A 出栈 进栈 设数组维数为M top=base,栈空,此时出栈,则下溢(underflow) top=M,栈满,此时入栈,则上溢(overflow) 栈顶指针top,指向实际栈顶 后的空位置,栈底base

3.1 栈 栈的存储结构: 入栈算法 出栈算法 在一个程序中同时使用两个栈 取栈顶元素 表示 3.1  栈 栈的存储结构: 表示 入栈算法 出栈算法 *避免栈“上溢”的办法是事先分配一个足够大的空间。但事先无法估计。实际上,各个栈的大小都是动态变化的,往往有这样的情况:即其中某个栈发生上溢,而其余的栈尚有很多空间。此时,我们可以设法调整空间,减少“上溢”的发生。 如果只有两个栈,则可以这样做(该做法经常被采用): 在一个程序中同时使用两个栈 M-1 栈1底 栈1顶 栈2底 栈2顶 取栈顶元素 表示

3.1 栈 (2)链栈 typedef struct LNode 结点定义 { int data; struct LNode *next; 3.1  栈 (2)链栈 栈顶 ^ …... top data next 栈底 typedef struct LNode { int data; struct LNode *next; }LNode; 结点定义 入栈算法 top ^ …... 栈底 top x p 出栈算法 q top ^ …... 栈底 top

1. 回文游戏:顺读与逆读字符串一样(不含空格) (1)读入字符串 (2)去掉空格(原串) (3)压入栈 (4)原串字符与出栈字符依次比较 3.2 栈的应用 1. 回文游戏:顺读与逆读字符串一样(不含空格) d a top (1)读入字符串 (2)去掉空格(原串) (3)压入栈 (4)原串字符与出栈字符依次比较 若不等,非回文 若直到栈空都相等,回文 字符串:“madam im adam” 2. 数制转换 例 把十进制数159转换成八进制数 (159)10=(237)8 159 8 19 2 2 3 7 余 7 余 3 余 2 top 7 3 2 3.1 算法:

3.2 栈的应用 3.行编辑程序 功能:接受用户从终端输入的程序和数据,并存入数据区。 允许用户输入出错,如发现刚输入的一个字符错时,可补进一个退格符“#”,表示前一个字符无效;如果发现当前输入的行内差错较多或难以补救,则可以键入一个退行符“@”,表示当前行中字符均无效。 如:whli##ilr#e(s#*s) outcha@putchar(*s=#++); 是:while(*s) putchar(*s++);

设行输入缓冲区为一个栈结构,每接受一个字符后便进行判断: (1)如果它既不是退格符#也不是退行符@,则将其压入栈顶; 3.2 栈的应用 算法思想 设行输入缓冲区为一个栈结构,每接受一个字符后便进行判断: (1)如果它既不是退格符#也不是退行符@,则将其压入栈顶; (2)如果是一个#,则从栈顶删除一个字符; (3)如果是一个@,则将栈清为空栈。 算法 3.2

a+(b*c+d)/e abc*d+e/+ 算符:运算符和界符。 算符的优先关系:<、=、> (见表3.1) 3.2 栈的应用 4.表达式求值 概念 前缀表达式 : +a b 中缀表达式 : a+b 后缀表达式 : a b+ 中缀表达式 后缀表达式(逆波兰表达式) a*b+c ab*c+ a+b*c abc*+ a+(b*c+d)/e abc*d+e/+ 算符:运算符和界符。 算符的优先关系:<、=、> (见表3.1) 这里重点介绍中缀表达式、后缀表达式求值。

3.2 栈的应用 刚读入的 栈顶的 表 3.1 算符间的优先关系

①设置两个工作栈,运算符栈OPTR 和操作数栈OPND。操作数栈也放表达式的运算结果; 3.2 栈的应用 (1)中缀表达式求值:操作数栈和运算符栈 算法思想 ①设置两个工作栈,运算符栈OPTR 和操作数栈OPND。操作数栈也放表达式的运算结果; ②置操作数栈为空栈,置运算符栈的栈底为表达式的起始符#; ③自左向右扫描表达式(即每次读一个字符); ④若遇操作数,则进栈OPND,转③ ---Reverse Polish Notation

⑤遇运算符,则运算符与OPTR栈顶进行优先数比较(同级的栈项为大,刚读入的为小): 若读的运算符大于OPTR栈顶项,则进栈,转③; 3.2 栈的应用 ⑤遇运算符,则运算符与OPTR栈顶进行优先数比较(同级的栈项为大,刚读入的为小): 若读的运算符大于OPTR栈顶项,则进栈,转③; 若栈顶项大,则栈顶运算符退栈,操作数栈顶两个元素退栈,并作一个运算,结果入栈OPND,转③; 若相等且为括号,则脱括号,转③ ; 若读的运算符为#,则转⑥; ⑥若运算符栈顶项为#,则操作数栈顶为计算结果,结束;否则出错 ---Reverse Polish Notation

3.2 栈的应用 例:扫描 A+B*C-D/(E+F)# # # A B*C + C 进栈 ‘+’>’#’ B * 3.2 栈的应用 例:扫描 A+B*C-D/(E+F)# # 操作数 运算符 操作数 # 运算符 A B*C + C 进栈 遇"-" <"*" 做B*C并进栈 ‘+’>’#’ B * ’ *’ >’+’ A + F + 操作数 # 运算符 A+B*C 操作数 # 运算符 A+B*C 进栈 ‘+’ > ‘( ‘ ‘(‘ > ’/’ ’/’ > ’-‘ ‘-’ > # ---Reverse Polish Notation "-"<"+" 做A+B*C 并进栈 E ( D / -

3.2 栈的应用 # A+B*C D - / E F ( + # A+B*C D - / ( 遇’)’ < ’+’ E+F 做E+F 3.2 栈的应用 操作数 # 运算符 A+B*C D - / E F ( + 操作数 # 运算符 A+B*C D - / ( 遇’)’ < ’+’ E+F 做E+F 操作数 # 运算符 A+B*C D - / E+F 操作数 # 运算符 A+B*C D/(E+F) - ’ ) ’ = ’( ‘ 脱括号 ‘做D/(E+F) ---Reverse Polish Notation ‘#’<‘/’

3.2 栈的应用 算法 D/(E+F) A+B*C - A+B*C-D/(E+F) # # 3.4 操作数 运算符 操作数 运算符 3.2 栈的应用 操作数 # 运算符 A+B*C D/(E+F) - 操作数 # 运算符 A+B*C-D/(E+F) ‘#’<’/’ 做D/(E+F) ‘#’<’/’ 做A+B*C-D/(E+F) ‘#’=‘#’ 操作数出栈 ---Reverse Polish Notation 即计算结果 算法 3.4

从左到右扫描向量IFX,重复下述两步操作,直到表达式尾。 ① 从IFX中取出下个TOKEN(数字、运算符、左括号、右括号); 3.2 栈的应用 (2)中缀表达式转为后缀表达式 设中缀表达式和后缀表达式分别在向量IFX和PFX中,用栈S实现中缀式转为后缀式,对IFX中表达式从左到右扫描,设TOKEN是扫描读到的符号,转换算法可描述如下: 栈初始化。 从左到右扫描向量IFX,重复下述两步操作,直到表达式尾。 ① 从IFX中取出下个TOKEN(数字、运算符、左括号、右括号);

操作符:如栈空或TOKEN比栈顶元素优先级高,将TOKEN进栈;否则,退栈并将退栈元素送入PFX,然后再将TOKEN与新栈顶元素比较之; 3.2 栈的应用 ② CASE TOKEN OF '(':将TOKEN压入栈S; 操作数:将操作数直接送入PFX; 操作符:如栈空或TOKEN比栈顶元素优先级高,将TOKEN进栈;否则,退栈并将退栈元素送入PFX,然后再将TOKEN与新栈顶元素比较之; ‘)' :退栈并将退栈元素送PFX,直到碰到左括号,左括号退栈不送PFX。 当遇到中缀表达式结束符号,连续退栈并送退栈元素到PFX,直至栈空。

c.若是运算符,从栈中弹出2个数,将运算结果再压入栈 d.若表达式输入完毕,栈顶即表达式值; 若表达式未输入完,转a 3.2 栈的应用 (3)后缀表达式求值步骤: a.读入表达式一个字符 b.若是操作数,压入栈,转d c.若是运算符,从栈中弹出2个数,将运算结果再压入栈 d.若表达式输入完毕,栈顶即表达式值; 若表达式未输入完,转a 后缀表达式:435*+ 例 计算 4+3*5 top 7 3 5 top 4 top 4 3 top 4 15 top 19 top

当一个函数在运行期间调用另一个函数时,在运行该被调用函数之前,需先完成三件事: 3.3 栈与递归的实现 当一个函数在运行期间调用另一个函数时,在运行该被调用函数之前,需先完成三件事: 将所有的实在参数、返回地址等信息传递给被调用函数保存 为被调用函数的局部变量分配存储区 将控制转移到被调用函数的入口 而从被调用函数返回调用函数之前,应该完成: 保存被调函数的计算结果 释放被调函数的数据区 依照被调函数保存的返回地址将控制转移到调用函数 由于函数的运行规则是:后调用先返回,因此各函数占有的存储管理应实行"栈式管理"

3.3 栈与递归的实现 1. 过程的嵌套调用 r s t 子过程2 r s 子过程1 r s t 子过程3 r 主程序 r s r

3.3 栈与递归的实现 例 递归的执行情况分析 2. 递归过程及其实现 递归:函数直接或间接的调用自身叫递归 实现:建立递归工作栈 3.3 栈与递归的实现 2. 递归过程及其实现 递归:函数直接或间接的调用自身叫递归 实现:建立递归工作栈 例 递归的执行情况分析 void print(int w) { int i; if ( w!=0) { print(w-1); for(i=1;i<=w;++i) printf(“%3d,”,w); printf(“/n”); } 运行结果: 1, 2,2, 3,3,3,

3.3 栈与递归的实现 3.递归调用执行情况如下: 1 print(0); (3)w=1 (2)w=2 (1)w=3 top (4)输出:1 3.3 栈与递归的实现 1 print(0); (3)w=1 (2)w=2 (1)w=3 top (4)输出:1 w (4)w=0 (3)w=1 (2)w=2 (1)w=3 top w 3.递归调用执行情况如下: 2 print(1); (2)w=2 (1)w=3 top (3) 输出:2, 2 w 3 print(2); (1)w=3 top (2) 输出:3, 3, 3 w (4)输出:1 (3) 1 (2) 2 (1) 3 top 返回 (3) 1 (2) 2 (1) 3 top (4) 0 主程序 (3) 输出:2, 2 (2) 2 (1) 3 top (1) print(w) w=3; (2) 输出:3, 3, 3 (1 ) 3 top 结束 (1)

3.3 栈与递归的实现 5.Tower of Hanoi问题 问题描述:有X,Y,Z三个塔座,X上套有n个直径不同的圆盘,按直径从小到大叠放,形如宝塔,编号1,2,3……n。要求将n个圆盘从X移到Z,叠放顺序不变,移动过程中遵循下列原则: 每次只能移一个圆盘 圆盘可在三个塔座上任意移动 任何时刻,每个塔座上不能将大盘压到小盘上 解决方法: n=1时,直接把圆盘从X移到Z n>1时,先把上面n-1个圆盘从X移到Y,然后将n号盘从X移到Z,再将n-1个盘从Y移到Z。即把求解n个圆盘的Hanoi问题转化为求解n-1个圆盘的Hanoi问题,依次类推,直至转化成只有一个圆盘的Hanoi问题

3.3 栈与递归的实现 X Y Z

3.3 栈与递归的实现 X Y Z

3.3 栈与递归的实现 X Y Z

3.3 栈与递归的实现 X Y Z

3.3 栈与递归的实现 X Y Z

3.3 栈与递归的实现 X Y Z

3.3 栈与递归的实现 X Y Z

3.3 栈与递归的实现 X Y Z

3.3 栈与递归的实现 X Y Z

3.3 栈与递归的实现 X Y Z

3.3 栈与递归的实现 X Y Z

递归工作栈保存内容:形参n,x,y,z和返回地址 返回地址用行编号表示 3.3 栈与递归的实现 X Y Z 执行情况: 递归工作栈保存内容:形参n,x,y,z和返回地址 返回地址用行编号表示 n x y z 返回地址

3.3 栈与递归的实现 main() { int m; printf("Input number of disks”); 3.3 栈与递归的实现 A B C 1 2 3 main() { int m; printf("Input number of disks”); scanf("%d",&m); printf(”Steps : %3d disks”,m); hanoi(m,'A','B','C'); (0) } void hanoi(int n,char x,char y,char z) (1) { (2) if(n==1) (3) move(1,x,z); (4) else{ (5) hanoi(n-1,x,z,y); (6) move(n,x,z); (7) hanoi(n-1,y,x,z); (8) } (9) } 3 A B C 0 3 A B C 0 2 A C B 6 3 A B C 0 2 A C B 6 1 A B C 6 A B C 3 A B C 0 2 A C B 6

3.3 栈与递归的实现 main() { int m; printf("Input the number of disks 3.3 栈与递归的实现 3 A B C 0 2 A C B 6 main() { int m; printf("Input the number of disks scanf("%d",&m); printf("The steps to moving %3d hanoi(m,'A','B','C'); (0) } void hanoi(int n,char x,char y,char z) (1) { (2) if(n==1) (3) move(1,x,z); (4) else{ (5) hanoi(n-1,x,z,y); (6) move(n,x,z); (7) hanoi(n-1,y,x,z); (8) } (9) } A B C 3 A B C 0 2 A C B 6 1 C A B 8 A B C 3 A B C 0 2 A C B 6 3 A B C 0

3.3 栈与递归的实现 main() { int m; printf("Input the number of disks 3.3 栈与递归的实现 main() { int m; printf("Input the number of disks scanf("%d",&m); printf("The steps to moving %3d hanoi(m,'A','B','C'); (0) } void hanoi(int n,char x,char y,char z) (1) { (2) if(n==1) (3) move(1,x,z); (4) else{ (5) hanoi(n-1,x,z,y); (6) move(n,x,z); (7) hanoi(n-1,y,x,z); (8) } (9) } 3 A B C 0 A B C 3 A B C 0 2 B A C 8 3 A B C 0 2 B A C 8 1 B C A 6 A B C 3 A B C 0 2 B A C 8

3.3 栈与递归的实现 main() { int m; printf("Input the number of disks 3 A B C 0 2 B A C 8 3.3 栈与递归的实现 main() { int m; printf("Input the number of disks scanf("%d",&m); printf("The steps to moving %3d hanoi(m,'A','B','C'); (0) } void hanoi(int n,char x,char y,char z) (1) { (2) if(n==1) (3) move(1,x,z); (4) else{ (5) hanoi(n-1,x,z,y); (6) move(n,x,z); (7) hanoi(n-1,y,x,z); (8) } (9) } A B C 3 A B C 0 2 B A C 8 1 A B C 8 A B C 3 A B C 0 2 B A C 8 3 A B C 0 栈空

3.3 栈与递归的实现 6.地图四染色问题 1# 紫色 2# 黄色 3# 红色 4# 绿色 1 2 3 4 5 6 7 3.3 栈与递归的实现 6.地图四染色问题 R [ 7][ 7 ] 1 2 3 4 5 6 7 1 2 3 4 5 6 7 1 0 0 0 0 1 0 0 1 1 1 1 1 0 1 0 1 0 1 1 0 1 0 1 1 0 1 0 1 1 0 1 1 0 0 1 0 0 1 1 0 0 0 0 0 0 0 0 0 (1) (2) (4) (5) (6) (7) (3) 1# 紫色 2# 黄色 3# 红色 4# 绿色 1 2 3 4 5 6 7 1 2 3 2 4 3 2 4 4 3 3 1

1.队列的定义及特点 3.4 队列 定义:队列是限定只能在表的一端进行插入,在表的另一端进行删除的线性表 队尾(rear)——允许插入的一端 3.4 队列 1.队列的定义及特点 定义:队列是限定只能在表的一端进行插入,在表的另一端进行删除的线性表 队尾(rear)——允许插入的一端 队头(front)——允许删除的一端 队列特点:先进先出(FIFO) a1 a2 a3…………………….an 入队 出队 front rear 队列Q=(a1,a2,……,an) 双端队列 a1 a2 a3…………………….an 端1 端2 入队 出队

3.4 队列 2.链队列 typedef struct Qnode 结点定义 { QElemType data; 3.4 队列 2.链队列 结点定义 typedef struct Qnode { QElemType data; struct Qnode *next; }Qnode, *QueuePtr; Typedef struct { QueuePtr front; QueuePtr rear; } 头结点 ^ …... front 队头 队尾 rear 设队首、队尾指针front和rear, front指向头结点,rear指向队尾

3.4 队列 空队 ^ front rear x入队 x ^ front rear y入队 x y ^ front rear x出队 x y 3.4 队列 front rear 空队 ^ front rear x入队 ^ x front rear y入队 x ^ y front rear x出队 x ^ y front rear y出队 ^

3.4 队列 入队算法 出队算法

3.4 队列 3.循环队列——队列的顺序存储结构 实现:用一维数组实现sq[M] 空队列条件:front==rear 3.4 队列 3.循环队列——队列的顺序存储结构 实现:用一维数组实现sq[M] rear 1 2 3 4 5 J4,J5,J6入队 J4 J5 J6 front Q.front=0 Q.rear=0 1 2 3 4 5 队空 1 2 3 4 5 front J1,J1,J3入队 rear 1 2 3 4 5 J1,J2,J3出队 J1 J2 J3 rear rear front J3 front rear J2 front J1 front 设两个指针front,rear,约定: Q.rear指示队尾元素的下一个位置; Q.front指示队头元素 初值Q.front=Q.rear=0 空队列条件:front==rear 入队列:sq[rear++]=x; 出队列:x=sq[front++];

3.4 队列 存在问题 设数组大小为M,则: 当front=0,rear=M时,再有元素入队发生溢出——真溢出 3.4 队列 存在问题 设数组大小为M,则: 当front=0,rear=M时,再有元素入队发生溢出——真溢出 当front0,rear=M时,再有元素入队发生溢出——假溢出 解决方案 队首固定,每次出队剩余元素向下移动——浪费时间 循环队列 基本思想:把队列设想成环形,让sq[0]接在sq[M-1]之后,若rear==M,则令rear=0; M-1 rear 1 front …... 实现:利用“模”运算 入队: sq[rear]=x; rear=(rear+1)%M; 出队: x=sq[front]; front=(front+1)%M; 队满、队空判定条件

3.4 队列 front rear rear J5 J4 J3,J4,J5出队 队空:front==rear J3 J6,J7,J8入队 3.4 队列 1 2 3 4 5 rear front J3 J4 J5 1 2 3 4 5 rear front 初始状态 J3,J4,J5出队 队空:front==rear J4 J5 J6 1 2 3 4 5 rear front J3 J8 J7 J6,J7,J8入队 解决方案: 1.另外设一个标志以区别队空、队满 2.少用一个元素空间: 队空:front==rear 队满:(rear+1)%M==front 队满:front==rear

循环队列的顺序存储结构 #define MAXQSIZE 100 // 最大队列长度 3.4 队列 循环队列的顺序存储结构 #define MAXQSIZE 100 // 最大队列长度 typedef struct {   QElemType *base;// 初始化的动态分配存储空间   int rear;    // 队尾指针,指向队尾元素的下一个位置   int front;   // 队头指针,指向队头元素   } SqQueue;

循环队列的基本操作的算法描述 3.4 队列 Status InitQueue (SqQueue &Q){ // 构造一个空队列 Q 3.4 队列 循环队列的基本操作的算法描述 Status InitQueue (SqQueue &Q){ // 构造一个空队列 Q Q.base = (QElemType *)malloc(MAXQSIZE *sizeof(QElemType)); // 为循环队列分配存储空间 if (!Q.base) exit(OVERFLOW); // 存储分配失败 Q.front = Q.rear = 0; return OK; } // InitQueue

int QueueLength (SqQueue Q){ // 返回队列Q中元素个数,即队列的长度 return ((Q.rear-Q.front+MAXQSIZE) % MAXQSIZE); }

3.4 队列 入队算法: 出队算法:

本章小结 栈和队列都属线性结构,因此它们的存储结构和线性表非常类似,同时由于它们的基本操作要比线性表简单得多,因此它们在相应的存储结构中实现的算法都比较简单,相信对大家来说都不是难点。 这一章的重点则在于栈和队列的应用。通过本章所举的例子学习分析应用问题的特点,在算法中适时应用栈和队列。

2. 如果进栈序列为123456,则能否得到435612和135426的出栈序列,并请说明为什么不能得到。 基础知识题 1. 进栈序列为123,则可能得到的出栈序列是什么? 2. 如果进栈序列为123456,则能否得到435612和135426的出栈序列,并请说明为什么不能得到。 3. 简述栈和线性表的差别。 4. 简述队列和栈这两种数据类型的相同点和差异处。