首页 数据结构第三章_栈和队列

数据结构第三章_栈和队列

举报
开通vip

数据结构第三章_栈和队列nullnull北京联合大学信息学院 张冰峰 办公室:北院A楼 五层信息系统教研部 电 话:64900518 邮 箱:xxtbingfeng@buu.com.cn第3章栈和队列第3章栈和队列本章要点 栈和队列的基本概念和基本运算。 栈和队列存储表示和基本运算的实现方法。 栈和队列应用。 本章要求 通过本章的学习应该掌握栈和队列逻辑结构和存储结构,以及栈和队列基本运算和算法实现。能理解和运用栈和队列的实际应用。 ...

数据结构第三章_栈和队列
nullnull北京联合大学信息学院 张冰峰 办公室:北院A楼 五层信息系统教研部 电 话:64900518 邮 箱:xxtbingfeng@buu.com.cn第3章栈和队列第3章栈和队列本章要点 栈和队列的基本概念和基本运算。 栈和队列存储表示和基本运算的实现方法。 栈和队列应用。 本章要求 通过本章的学习应该掌握栈和队列逻辑结构和存储结构,以及栈和队列基本运算和算法实现。能理解和运用栈和队列的实际应用。 null 从数据结构上看,栈和队列也是线性表,不过是两种特殊的线性表.被称作为操作受限的线性表。 3.1栈 3.1.1栈的概念及运算 1.栈的定义 栈(Stack)是限制仅在表的一端进行插入和删除运算的线性表,通常称插入、删除的这一端为栈顶(Top),另一端称为栈底(Bottom)。栈的插入操作通常称为入栈或进栈(push),而栈的删除操作则称为出栈或退栈(pop)。当表中没有元素时称为空栈。 null 根据上述定义可知,栈顶元素总是最后入栈的,因而是最先出栈;栈底元素总是最先入栈的,因而也是最后出栈。这种表是按照后进先出(LIFO,Last In First Out )的原则组织数据的,因此,栈也被称为“后进先出”的线性表。a1 an 入栈 出栈 栈顶 top 栈底 bottom 图3.1 栈的示意图 ... a2 栈的基本运算栈的基本运算 2.栈的运算 (1)创建空栈 SeqStack *InitStack() (2)判栈空 isEmptyStack(SeqStack *S) (3)进栈 SeqStack Push(SeqStack *S ,datatype x) (4)退栈 datatype pop(SeqStack *S ) (5)取栈顶 GetTop(SeqStack *S) 与Pop(s)的不同处在于GetTop(s)不改变栈的状态。 栈是一种特殊的线性表,因此栈可采用顺序存储结构存储,也可以使用链式存储结构存储。3.1.2 栈的顺序存储结构3.1.2 栈的顺序存储结构顺序栈的类型和变量定义如下: #define Maxsize 100 /* 栈可能达到的容量*/ typedef int datatype /* 栈元素的数据类型*/ typedef struct { datatype stack[Maxsize]; int top; }SeqStack; /* 顺序栈的类型定义*/ SeqStack *s;null鉴于C语言中数组的下标约定是从0开始的,因而使用C语言的一维数组作为栈的顺序存储结构时,应设栈顶指针S->top=-1时为空栈,s->top= Maxsize -1为栈满。2.顺序栈的基本运算算法2.顺序栈的基本运算算法 栈是一个动态结构,而数组是一静态结构,会出现所谓的溢出问题:包括上溢(Overflow) 和下溢(Underflow)。 在进行进栈和出栈运算前要判断栈的状态。 创建空栈 SeqStack *InitStack() { SeqStack *S; S=(SeqStack *)malloc(sizeof(SeqStack)); if(!S) {printf(“空间不足”);null return NULL;} else {S->top=-1; return S;} } 2.取栈顶元素datatype GetTop(SeqStack *S) 3.入栈 SeqStack *Push(SeqStack *S,datatype x) 4.出栈 Pop(SeqStack *S) 5.判栈空 StackEmpty(SeqStack *S) 3.1.4 栈的链式存储结构3.1.4 栈的链式存储结构 栈的链式存储结构称为链栈。在一个链栈中,栈底就是链表的最后一个结点,而栈顶总是链表的第一个结点。因此,新入栈的元素即为链表新的第一个结点,只要系统还有存储空间,就不会有栈满的情况发生。一个链栈可由栈顶指针top唯一确定,当top为null时,是一个空栈。top…top…q修改栈顶指针top=p修改栈顶指针top=top->nextnull(a)A∧toptop(b)(s)top(a)含有两个元素A、B的栈;(b)插入元素C后的栈;(c)删除元素C、B后的栈栈的链式存储结构和操作实现 栈的链式存储结构和操作实现 结点结构定义 typedef struct node { datatype data; struct node *next; }LinkStack; LinkStack *top;栈的链式存储结构和操作实现栈的链式存储结构和操作实现 (1)判空栈int StackEmpty(LinkStack *top) { return (top= =NULL) } (2)取栈顶datatype GetTop(LinkStack *top) (3)入栈LinkStack *Push(LinkStack *top,datatype x) (4)出栈顶LinkStack *Pop(LinkStack *top)3.2栈的应用3.2栈的应用 栈具有后进先出的特点,凡问题求解具有后进先出的特性,求解过程必然需要用到栈。 (1) 数制转换 (2)括号匹配问题 (3)子程序调用 (4)利用栈逆置一个带头结点的单链表3.2栈的应用3.2栈的应用1.用栈实现递归函数 在各种程序设计语言中都有子程序(或称函数、过程)调用功能。而子程序也可以调用其它的子程序,甚至可以直接或间接地调用自,这调用关系就是递归。下面以求阶乘的递归方法为例,来分析计算机系统如何处理这种递归调用关系的。 求n!的递归方法的思路是: 相应的C语言函数是: float fact(int n) { float s; if (n= =0||n= =1) s=1; else s=n*fact(n-1); return (s); } 在该函数中可以理解为求n!用fact(n)来表示,则求(n-1)!就用fact(n-1)来表示。若求5!,则有3.2栈的应用3.2栈的应用 main() { printf(“5!=%f\n”,fact(5)); } 图3.5给出了递归调用执行过程。从图中可看到fact函数共被调用5次,即fact(5)、fact(4)、fact(3)、fact(2)、fact(1)。其中,fact(5)为主函数调用,其它则为在fact函数内的调用。每一次递归调用并未立即得到结果,而是进一步向深度递归调用,直到n=1或n=0时,函数fact才有结果为1,然后再一一返回计算,最终得到结果。null图3.5 递归调用过程示意图3.2栈的应用3.2栈的应用计算机系统处理上述过程时,其关键是要正确处理执行过程中的递归调用层次和返回路径,也就是要记住每一次递归调用时的返回地址。在系统中是用一个线性表动态记忆调用过程中的路径,其处理原则为: (1)在开始执行程序前,建立一个线性表,其初始状态为空。 (2)当发生调用(递归)时,将当前的调用的返回点地址插入到线性表的末尾; (3)当调用(递归)返回时,其返回地址从线性表的末尾取出。 根据以上的原则,可以给出线性表中的元素变化状态如图3.6所示(以递归调用时n值的变化为例): 3.2栈的应用3.2栈的应用汉诺塔问题 假设有3个塔座X、Y、Z,在塔座X上插有n个直径大小各不相同、从大到小编号为1,2,…,n的圆盘。现要求将X轴上的n个圆盘移至塔座Z上并仍按同样顺序叠排。 圆盘移动时必须遵循下列规则: (1)每次只能移动一个圆盘 (2)圆盘可以插在X、Y和Z中任一塔座上 (3)任何时刻都不能将一个较大的圆盘压在 较小的圆盘之上。3.2栈的应用3.2栈的应用void Hanoi(int n,char x,char y,char z) { if(n==1) move(x,1,z) else hanoi(n-1,x,z,y); move(x,n,z); hanoi(n-1,y,x,z); } xyz3.2栈的应用3.2栈的应用Hanoi(3,a,b,c) Hanoi(2,a,c,b) Hanoi(1,a,b,c) A-C Move(a,2,b) A-B Hanoi(1,c,a,b) C-B Move(a,3,c) A-C Hanoi(2,b,a,c) Hanoi(1,b,c,a) B--A Move(b,2,c) B--C Hanoi(1,a,b,c) A--C A-C A--B C--B A--C B--A B--C A--C 3.3队列3.3队列3.3.1队列的概念及运算 队列(Queue)也是一种运算受限的线性表。它允许在表的一端进行插入,而在另一端进行删除。 允许删除的一端称为队头(Front),允许插入的一端称为队尾(Rear)。 队列的插入操作通常称为入队或进队,而队列的删除操作则称为出队或退队。当队列中无数据元素时,称为空队列。 根据上述队列定义可知,队头元素总是最先进队列的,也总是最先出队列;队尾元素总是最后进队列,因而也是最后出队列。这种表是按照先进先出(FIFO,First In First Out )的原则组织数据的,因此,队列也被称为“先进先出”表。3.3队列3.3队列假若队列q={a1,a2,a3,…,an},进队列的顺序为a1 ,a2,a3,…,an,则队头元素为a1,队尾元素为an。 图3.8是一个队列的示意图,通常用指针f (front)指示队头的位置,用指针r(rear)指向队尾。 a1 a2 a3 ai an front rear 图3.8 队列的示意图 … … 3.3队列3.3队列2.队列的基本操作 (1)InitQueue(Q)构造空队列 (2)QueueEmpty(Q) 判断队列空 (3)QueueLength(Q) 求队列长度 (4)GetHead(Q) 返回队头 (5)EnQueue(Q,x) 入队列 (6)DeQueue(Q) 删除队头元素 队列是一种特殊的线性表,因此队列可采用顺序存储结构存储,也可以使用链式存储结构存储。3.3.2顺序队列的数组表示3.3.2顺序队列的数组表示 队列的顺序存储结构称为顺序队列。也就是利用一组地址连续的存储单元依次存放队列中的数据元素。一般情况下,使用一维数组来作为队列的顺序存储空间,由于队列的队头和队尾位置均是变化的,因而要设置两个指针:分别指向当前队头元素和队尾元素在数组中位置。 队头指针指出实际队头元素所在的位置,队尾指针指出队尾元素所在位置的下一个位置。3.3.2顺序队列的数组表示3.3.2顺序队列的数组表示012345rearfront012345rearfront012345rearfront012345rearfront(a)空队列(b)a、b入队(c)a、b出队,c、d入队(d)假溢出循环队列循环队列空队列时再做出队操作便会产生“下溢”。队满的条件是当前队列长度等于向量空间的大小,队满时再做入队操作会产生“上溢”。 如果当前尾指针等于向量上界,即使队列不满,再做入队操作也会引起溢出。此时不能作入队操作,但当前队列并不满,这种现象叫“假溢出”。产生该现象的原因是,被删元素的空间在元素删除以后就永远使用不到。 解决这个问题有两种可行的方法: (1)采用平移元素的方法,当发生假溢出时,就把整个队列的元素平移到存储区的首部,然后再插入新元素。这种方法需移动大量的元素,因而效率是很低的。2.循环队列2.循环队列(2)将顺序队列的存储区假想为一个环状的空间,如图所示。假想paqu->q[0]接在paqu->q[MAXNUM-1]的后面。当发生假溢出时,将新元素插入到第一个位置上,这样做,虽然物理上队尾在队首之前,但逻辑上队首仍然在前。入列和出列仍按“先进先出”的原则进行,这就是循环队列。 很显然,方法二中不需要移动元素,操作效率高,空间的利用率也很高。maxsize-1 0 1 rear front null循环队列的类型定义 #define MaxSize 100 typedef struct { datatype data[MaxSize]; int front; int rear; }SeqQueue;null012345reara4a5front012345reara4a5front012345rearfronta9a8a7a6循环队列满的条件: (rear+1)%rearMaxSize= = front 循环队列空的条件: rear= =front循环队列的基本操作循环队列的基本操作(1)构造空队列 SeqQueue *InitQueue() { SeqQueue *q; q=(SeqQueue *)malloc(sizeof(SeqQueue)); q->front=q->rear=0; return q; } (2)判断队列空 int QueueEmpty(SeqQueue *q) { return (q->front = =q->rear); }null(3)入队int EnQueue(SeqQueue *q,datatype x) (4)出队datatype DeQueue(SeQueue *q) 3.3.3 队列的链式存储结构3.3.3 队列的链式存储结构队列的链式存储结构称为链队列,它是限制仅在表头删除和表尾插入的单链表。在链队列中设定两个指针(头指针和尾指针)分别指向队列的头和尾。 为了操作方便,在队头结点前附加一个头结点,且头指针指向头结点。 null头结点队头队尾。。。 ∧rearfront结点类型定义: typedef Struct Qnode { datatype data; Struct Qnode *next; }Qnode; 链队列类型定义: typedef struct { Qnode *front; Qnode *rear; }LinkQueue;∧frontrearfrontrear∧xfrontrearx∧yfrontrearx∧ynullLinkQueue *InitQueue() { LinkQueue *q; Qnode *p; q=(LinkQueue*)malloc(sizeof(LinkQueue)); p=(Qnode*)malloc(sizeof(Qnode)); p->next=NULL; q->front=q->rear=p; return q; }(1)构造一个空队列链队列的基本操作链队列的基本操作取队头元素 datatype GetHead(LinkQueue *Q) 入队 void EnQueue (LinkQueue *Q,datatype x) 出队 datatype DeQueue(LinkQueue *Q) 队列的应用队列的应用在计算机科学领域中,解决主机与外部设备之间的速度不匹配问题,解决多用户引起的资源竞争问题等,都需要利用队列来处理。 (1)打印杨辉三角形 (2)迷宫问题
本文档为【数据结构第三章_栈和队列】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_963709
暂无简介~
格式:ppt
大小:549KB
软件:PowerPoint
页数:0
分类:
上传时间:2010-03-09
浏览量:34