第三章 栈和队列 栈和队列是两种重要的数据结构。

Slides:



Advertisements
Similar presentations
阻塞操作. 在 linux 里,一个等待队列由一个 wait_queue_head_t 类型的结构来描述 等待队列的初始化: static wait_queue_head_t testqueue; init_waitqueue_head(&testqueue);
Advertisements

一、算法的基本概念 二、数据结构 三、栈和队列 四、排序方法 五、二叉树
问题的提出: 例1 把十进制整数转换为二至十六之间的任一进制数输出。
数据结构 复 习.
实用数据结构基础 第3章 栈.
第五讲 队列.
数据结构——树和二叉树 1/96.
第3章 栈和队列 3.1 栈 3.2 队列 3.3 应用.
第3章 栈和队列.
第6章 佇列(Queues) 6-1 佇列的基礎 6-2 佇列的表示法 6-3 環狀佇列 6-4 雙佇列.
主要内容: 1.第一部分 概述 2.第二部分 线性表、栈、队列
第三章 栈和队列 Stack and Queue
第三章栈和队列 栈 队列 递归.
佇列 (Queue).
資料結構 第5章 佇列.
数据结构.
第十章 基本数据结构 链表结构 栈结构 队列结构 主讲:李祥 时间:2015年10月.
强连通分量 无向图 1、任意两顶点连通称该图为连通图 2、否则将其中的极大连通子图称为连通分量 A D C B E 有向图
第3章 顺序存储结构的表、堆栈和队列 3.1 顺序存储结构 3.2 表和顺序表 3.3 堆栈和顺序堆栈 3.4 队列和顺序队列
Ch.3 栈和队列 黄刘生 中国科学技术大学计算机系 国家高性能计算中心(合肥)
线性表小结 元素之间的线性关系 顺序表 顺序表:元素相邻存储 单链表:后继指针链接 一维数组 给定下标随机存取
本 章 说 明 3.1 栈 3.2 栈的应用举例 3.3 栈与递归的实现 3.4 队 列 本 章 小 结 返回主目录.
cn/~dongeliu/dsa.html 刘 东 信息学院6系 中国科学技术大学
第3章 栈和队列(二) 1/.
第3章 栈和队列 丽水学院工学院.
1、栈及其实现 2、栈的应用 3、队列及其实现 4、优先级队列 5、链式队列 6、队列应用
第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++程式設計進階 堆疊與佇列(Stack & Queue) 講師:林業峻 CSIE, NTU 6/ 21, 2010.
第一章 绪论.
陈海明 副教授 信息学院 计算机系 电子信息类非计算机专业选修课 程序设计实践 陈海明 副教授 信息学院 计算机系
内容回顾 线性表的定义和特点 线性表的顺序存储及查找、插入和删除.
教 师:曾晓东 电 话: E_mail: 计算机软件技术基础 教 师:曾晓东 电 话: E_mail:
第3章 栈和队列 3.1 栈 本章主题:栈和队列的应用 教学目的:掌握栈和队列的应用方法,理解栈的重要作用
第3章 栈与队列.
数 据 结 构 刘家芬 Sept 2012.
第二章 Java语言基础.
第三章 栈和队列.
#define STACK_INIT_SIZE 10
第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++语言程序设计.
顺序表的删除.
线 性 代 数 厦门大学线性代数教学组 2019年4月24日6时8分 / 45.
队列及其实现.
单链表的基本概念.
第 四 讲 线性表(二).
第 六 讲 栈和队列(一).
本章的基本内容是: ⑴栈和队列的定义及操作特性; 第3章 特殊线性表—栈、队列和串 ⑵栈和队列的两种存储方法和基本运算的实现;
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
实验目的:掌握数据的顺序存储结构及它们在计算机中的操作。 实验内容:
第七讲 栈和队列(二) 1/.
第3章 栈和队列 3.1 栈 3.2 队列.
Chapter 2 Entity-Relationship Model
第三章 栈和队列.
昆山爱达人信息技术有限公司 QQ: 本节内容 1.栈的链式存储结构及实现 2.栈的应用.
第二章 线性表 东南大学计算机学院 方效林 本课件借鉴了清华大学殷人昆老师 和哈尔滨工业大学张岩老师的课件.
Presentation transcript:

第三章 栈和队列 栈和队列是两种重要的数据结构。 从结构特性角度看,栈和对列也是线性表,其特殊性在于它们的基本操作是线性表的子集,是操作受限的线性表,可称为限定性的数据结构。 从数据类型角度看,其操作规则与线性表大不相同,是完全不同于线性表的抽象数据类型。

第一节 栈 一、栈的定义 栈是限定在表的一端进行插入和删除操作的线性表。 插入:称为进栈(或压栈)。 删除:称为出栈(或退栈)。 栈顶(top):允许进行插入和删除操作的一端。 栈底(bottom):不允许插入和删除操作的一端。 栈底 … an a2 a1 栈顶 基本操作: Initstack(&s): 栈初始化 Destroystack(&s):撤消栈 Clearstack(&s):置栈空 Stackempty(s) :判栈空 Stacklength(S):求栈中元素个数 Gettop(S,&e): 取栈顶元素 Push(&S,e): 入栈 Pop(&S,&e): 出栈 特点:后进先出----LIFO Last In First Out

栈的表示与实现 三、栈的顺序存储结构----顺序栈 利用一组地址连续的存储单元依次存放从栈底到栈顶的数据元素。 顺序栈存储结构定义: #define STACK_INIT_SIZE 100 //存储空间初始分配量; #define STACKINCREMENT 10 //存储空间分配增量 typedef struct { SElemType *base; SElemType *top; int stacksize; }SqStack; Base指向存储空间开始地址,top指示栈顶当前位置。 若栈空间未分配,则base为NULL; top==base:栈空 top-base==stachsize:栈满 元素进栈:在top位置插入元素,top增1 元素出栈:top减1。 top指针始终指向栈顶元素的下一个位置 。

顺序栈操作的实现 Status Initstack(Sqstack &s) { s.base=(SElemType *) 1、栈初始化:分配初始存储空间,初始化各变量。 Status Initstack(Sqstack &s) { s.base=(SElemType *) malloc(STACK_INIT_SIZE*sizeof(SElemType)); if(!b.base) exit(OVERFLOW); s.top=s.base; s.stacksize= STACK_INIT_SIZE ; return Ok; }

顺序栈操作的实现 2、撤消栈:释放栈空间。 status Destroystack(SqStack &s) { if(s.base) { free(s.base); s.base=NULL;return OK;} return ERROR; } 3、置栈空:将栈设置成空栈。 status Clearstack(SqStack &s) { if(s.base) { s.top=s.base;return OK;} 4、取栈顶元素:返回栈顶元素的值。 status GetTop(SqStack s,SElemType &e) { if(s.top==s.base) return ERROR; e=*(s.top-1); return OK

顺序栈操作的实现 if(!b.base) exit(OVERFLOW); e e 5、入栈操作:把元素压入栈中。 status Push(SqStack &s,SElemType e) { if(s.top-s.base>=s.stacksize) { s.base=(SElemType *)ralloc(s.base, (s.tacksize+STACKINCREMENT)*sizeof(SElemType)); if(!b.base) exit(OVERFLOW); s.top=s.base+s.stacksize; s.stacksize+=STACKINCREMENT; } *s.top=e; s.top++; return OK; top e B A base top B A base e 压栈操作

顺序栈操作的实现 { if (s.top==s.base) return ERROR; e=*(--s.top) return Ok } 6、出栈操作:删除栈顶元素。 Status Pop(Sqstack &s,Selemtype &e) { if (s.top==s.base) return ERROR; e=*(--s.top) return Ok } top Y B A base Y top B A base 出栈操作

链式栈的实现 用线性链表表示栈的存储结构,称为链栈。 链表头指针始终指向栈顶,同样用top表示。 无必要加头结点,栈空时:top=NULL 入栈:每当一个元素进栈时,申请一个新结点,插入到表头。 出栈:每当一个元素出栈时,从表头释放一个结点。 链栈结点结构描述如下 typedef struct stacknode{ ElemType data; struct stacknode *next; }StackNode; typedef struct { StackNode *top; }LinkStack; Data next S.top 栈顶 栈底

第二节 栈的应用 一、数制转换 将一个非负的十进制整数N转换为另一个等价的B进制数。 方法:不断用N及其商去除以B求余数直到商为0为止,所得余数的反序排列就是N的B进制表示。 5310的八进制表示  (53)10=(65)8 N   余数   商 53 5 6 6 6 0 5310的二进制表示  (53)10=(110101)2 N   余数   商 53 1 26 26 0 13 13 1 6 6 0 3 3 1 1 1 1 0 5310的四进制表示  (53)10=(311)4 N    余数   商 1 13 1 3 3 3 0 实现方法:用一个栈来存放产生的余数,然后从栈顶到栈底依次输出余数就是所求的B进制数。

栈的应用 算法: typedef int DataType; void Comversion(int N,int B) { int i; SeqStack S; InitStack(S); while(N) { Push(&S,N%B); N=N/B; } while(!StackEmpty(S)) { Pop(S,i); printf(“%d”,i); 算法的时间复杂度 O(logBN)。

栈的应用—表达式求值 一、算术四则运算法则: 先乘除后加减 从左至右 先括号内后括号外 方法:对运算符建立优先关系矩阵,按优先关系对表达式进行处理。 算符:运算符和界符。 根据法则1:乘除优先于加减,乘除优先级相同,加减优先级相同。 根据法则2:相邻两个同级运算符左优先。 根据法则3:“(”前面的运算符优先级低于“(”的优先级。“(”的优先级低于右边相邻算符。“)”左边的算符高于“)”的优先级。

栈的应用—表达式求值 + - * / ( ) # > < =

栈的应用—表达式求值 处理过程: 设置两个栈:操作数栈OPND和运算符栈OPTR。 设“#”表示表达式的开始和结束(作为界符),即 #表达式# 1、首先置操作数栈为空栈,把“#”移进运算符栈。 2、从左至右扫描表达式,凡遇到操作数一律进OPND栈;若遇到运算符,则把栈顶运算符与扫描运算符的优先数进行比较:若 < 扫描运算符进OPTR栈 = 若“(”和“)”,栈顶符号出栈;若为#,运算结束。 > 取OPND栈顶操作数与OPTR栈顶算符进行运算,参与运算的操作数和运算符出栈,运算结果进OPND栈 若表达式处理完,OPTR栈为#,OPND栈中只剩一项,表示表达式的运算结果,则分析成功。否则表明表达式有错。

栈的应用—表达式求值 例:3+5*(7-2) 步数 OPTR OPND 表达式 主要操作 1 # 3+5*(7-2)# push(OPND, 3) 2 # 3 +5*(7-2)# push(OPTR,’+’) 3 #+ 3 5*(7-2)# push(OPND, 5) 4 #+ 3,5 *(7-2)# push(OPTR,’*’) 5 #+* 3,5 (7-2)# push(OPTR,’(’) 6 #+*( 3,5 7-2)# push(OPND,7) 7 #+*( 3,5,7 -2)# push(OPTR,’-’) 8 #+*(- 3,5,7 2)# push(OPND,2) 9 #+*(- 3,5,7,2 )# opreate(7,’-’,2) 10 #+*( 3,5,5 )# pop(OPTR,‘(’),去掉‘)’ 11 #+* 3,5,5 # opreate(5,’*’,5) 12 #+ 3,25 # opreate(3,’+’,25) 13 # 28 # 成功

第三节 栈与递归的实现 递归函数:若在一个函数内部有直接或通过调用函数又间接调用自身,则称它们是递归函数,或者说是递归定义的。 1 n=0 n!= n*(n-1)! n>0 1 n<=1 f(n)= n*f(n-1)! n>0 int f( int n) { if (n <=1) then return (1) else return (n *f(n-1)); } Y=f(5); 1 f(1) return(1) 2 f(2) 递归函数的执行:递归调用通过栈实现;系统每调用一次函数, 系统就在栈顶分配该函数所需空间。 return(2) 3 f(3) return(6) 4 f(4) return(24) 5 f(5) return(120)

栈与递归的实现 递归算法设计一般分两步 : ①将规模较大的原问题分解为一个或多个规模更小,但具有类似于原问题特性的子问题,即较大的问题递归地用较小的子问题来描述,解原问题的方法同样可用来解这些子问题。 ②确定一个或多个无须分解、可直接求解的最小子问题。 第一步称为递归步骤,第二步称为递归的终止条件。 在递归步骤里分解问题时,应使子问题相对于原问题更接近于递归终止条件,从而保证经过有限次递归步骤后达到递归终止条件而结束递归。

第四节 队列 队列是限定在表的一端进行插入,在另一端进行删除的线性表。 a1 a2 … an 一、队列的定义: 队头(Front):允许删除的一端。 队尾(Rear):允许插入的一端。 基本操作: InitQueue (&Q): 队列初始化 DestroyQueue (&Q):撤消队列 ClearQueue (&Q):置队列空 QueueEmpty(Q) :判队列空 Queuelength(Q):求队列元素个数 Gethead(Q,&e): 取队列头元素 EnQueue (&Q,e): 入队列 DeQueue (&Q,&e):出队列 a1 a2 … an 删除 插入 特点:先入队列的元素总是先离开队列,所以称队列为先进先出(First In First Out)的线性表,简称FIFO。

队列的链式表示及实现 typedef struct QNode{ QElemType data; Struct QNode *next; 二、链队列:用线性链表表示队列的存储结构。 头指针----指向删除的一端 尾指针----指向插入的一端 链队列结点结构描述如下 typedef struct QNode{ QElemType data; Struct QNode *next; }Qnode,*QueuePtr; typedef struct { QueuePtr front; QueuePtr rear; }LinkQueue; LinkQueue Q; Q.front Q.reart

链队列基本操作 置空队列:保留头结点,头、尾指针置成初始状态。 1、队列初始化:建立链队列头结点,初始化头、尾指针。 Status Initqueue(linkqueue &Q) { Q.front =Q.rear=(QueuePtr)malloc(sizeof(Qnode)); Q.front->next=NULL; return OK; } 2、撤消队列:删除队列中所有结点(包括头结点)。 Status Destroyqueue(linkqueue &Q) { while (Q.front) {p= Q.front->next; free(Q.front); Q.front= p; 置空队列:保留头结点,头、尾指针置成初始状态。

链队列基本操作 3、入队操作:为入队元素申请结点,并插入到队尾。 Q x ۸ e ۸ Status Enqueue(linkqueue &Q,Qelemtype e) { p=(Qnode *)malloc(sizeof(Qnode)); if(!p) exit(OVERFLLOW); p->data=e; p->next=NULL; Q.rear->next=p; Q.rear=p; return OK; }

链队列基本操作 Status Dequeue(linkqueue &Q,Qelemtype &e) 3、出队操作:删除队头结点,并返回被删结点的值。 Q x z ۸ y Status Dequeue(linkqueue &Q,Qelemtype &e) { if (Q.front==Q.rear) return ERROR; p=Q.front->next; e=p->data; Q.front->next =p->next; if (Q.rear==p) Q.rear=Q.front; free(p); return OK; }

队列的顺序表示及实现 四、顺序队列:队列的顺序存储分配称为顺序队列。 顺序队列存储结构描述如下 #define MAXQSIZE 100 typedef struct { QElemType *base; int front; int rear; }SqQueue; SqQueue Q; 操作: 初 始:Q.front=Q.rear=0 元素进队:Q.base[Q.rear]=x;Q.rear++; 元素出队:e=Q.base[Q.front];Q.front++; 队 列 空:Q.front==Q.rear 队 列 满:Q.rear==MAXQSIZE

队列的顺序表示及实现 a3 a2 a1 四、顺序队列操作可能出现的问题 设MAXQSIZE=6 再有元素进队会怎样? a6 a5 a4 Q.rear a4 a5 a6 出队 Q.front a4 a5 a6 Q.rear 进队 Q.front Q.rear Q.front 初态 Q.front a1 a2 a3 Q.rear 进队 Q.rear a1 a2 a3 出队 Q.front

队列的顺序表示及实现 a2 an a1 删除 Q.front 插入 队满的三种情况: 1、所有单元都有元素; 2、部分单元有元素; 3、所有单元均无元素。 当队满时再要插入元素,称为上溢。 假上溢:队空间中还有存储单元未使用,但不能再插入元素。 假上溢原因:头、尾指针值总是不断增加,已使用过的单元无法再使用。 解决假上溢的方法: 1、将队中元素依次向队头方向移动。 缺点:浪费时间。每移动一次,队中元素都要移动。 2、将队空间设想成一个循环的表,即分配给队列的m个存储单元可以循环使用,当rear为m时,若向量的开始端空着,又可从头使用空着的空间。当front为m时,也是一样。 Q.front a1 a2 an Q.rear 删除 插入

循环队列 实现方法:模(mod) 运算。 插入元素: Q.base[Q.rear]=x; Q.rear=(Q.rear+1)% MAXQSIZE; 删除元素: x=Q.base[s.front] Q.front=(Q.front+1)% MAXQSIZE 循环队列:循环使用为队列分配的存储空间。 问题:队空队满都有:Q.front=Q.rear 区分队空队满的方法: 1、设置一个标志字段Q.tag区分队空队满(初值:tag=0 ) Q.tag=0 Q.front=Q.rear 队空 Q.tag=1 Q.front=Q.rear 队满 若进队操作前tag=0,进队操作后有Q.front=Q.rear,则置tag=1.   2、少用一个元素空间,m个元素单元最多只存放m-1个元素,且 front=rear ----队空 在入队时,若(Q.rear+1)%MAXQSIZE=Q.front,则为队满。 3、设置一个计数器记录队列中元素的个数。

循环队列算法 Status InitQueue(SqQueue &Q) { Q.base=(QElemType*) 1、循环队列初始化:为队列分配存储空间,头尾指针赋初值。 Status InitQueue(SqQueue &Q) { Q.base=(QElemType*) malloc(MAXQSIZE*sizeof(QElemType)); if(!Q.base) exit(OVERFLOW); Q.front =Q.rear=0; return OK; } 2、求队列长度 Status QueueLength(SqQueue Q) { return (Q.rear-Q.front+Maxsise)%Maxsize;

循环队列算法 Status Enqueue(sqqueue &Q,Qelemtype e) 3、入队操作:在队尾插入新元素。 Status Enqueue(sqqueue &Q,Qelemtype e) { if ((Q.rear+1)%Maxsize==Q.front) return ERROR; Q.base[Q.rear]=e; Q.rear=(Q.rear+1)%Maxsize; return OK; }

循环队列算法 { if (Q.front == Q.rear ) return ERROR; e=Q.base[Q.front]; 4、出队操作:删除队头元素,并返回队头元素的值。 Status DeQueue(SqQueue &Q,QElemType &e) { if (Q.front == Q.rear ) return ERROR; e=Q.base[Q.front]; Q.front=(Q.front+1)%Maxsize; return OK; }

队列的应用 二、队列的应用 1、脱机打印输出:按申请的先后顺序依次输出。 2、多用户系统中,多个用户排成队,分时地循环使用CPU和主存。 3、按用户的优先级排成多个队,每个优先级一个队列。 4、时时控制系统中,信号按接收的先后顺序依次处理。 5、网络信道信息传输,按到达的时间先后顺序依次进行。

作业 P22 3.3 3.4 3.5 3.7 3.9 3.13 3.15 3.21 3.30 3.31 3.17 √ 3.25 √ 3.29 √ 实验:下列题中任选一题 P96 2.1 停车场管理 2.5 算术表达式求值