收藏 分享(赏)

第三章第三讲栈和对列.ppt

上传人:11xg27ws 文档编号:8222195 上传时间:2019-06-15 格式:PPT 页数:47 大小:390KB
下载 相关 举报
第三章第三讲栈和对列.ppt_第1页
第1页 / 共47页
第三章第三讲栈和对列.ppt_第2页
第2页 / 共47页
第三章第三讲栈和对列.ppt_第3页
第3页 / 共47页
第三章第三讲栈和对列.ppt_第4页
第4页 / 共47页
第三章第三讲栈和对列.ppt_第5页
第5页 / 共47页
点击查看更多>>
资源描述

1、1,第三讲 栈和队列,栈和队列是两种特殊的线性表,是操作受限的线性表,称限定性线性表.,3.1 栈(stack) 栈的定义和特点 定义:限定仅在表尾进行插入或删除操作的线性表,表尾栈顶,表头栈底,不含元素的空表称空栈. 特点:先进后出(FILO)或后进先出(LIFO),2,3.1.1顺序栈 实现:一维数组s1M;,栈顶指针top,指向实际栈顶 元素位置,初值为0.,进栈,A,出栈,栈满,B,C,D,E,F,设数组为s1M; top=0,栈空,此时出栈,则下溢(underflow) top=M,栈满,此时入栈,则上溢(overflow),栈空,3,栈- 结论:后进先出(Last In First

2、 Out),简称为LIFO线性表。举例1:家里吃饭的碗,通常在洗干净后一个一个地落在一起存放,在使用时,若一个一个地拿,一定最先拿走最上面的那只碗,而最后拿出最下面的那只碗。 举例2:堆放在桌上的课本,在使用时,若一个一个地拿,一定最先拿走最上面的那本书,而最后拿出最下面的那本书。,4,思考题:一个栈的输入序列为1 2 3,若在入栈的过程中允许出栈,不可能得到的出栈序列是什么? A) 123;b) 132;c) 231;d)213;e) 312;,解:可以通过穷举所有可能性来求解: 1入1出, 2入2出,3入3出, 即123; 1入1出, 2、3入,3、2出, 即132; 1、2入,2出, 3

3、入3出, 即231; 1、2入,2、1出,3入3出, 即213; 1、2、3入,3、2、1出, 即321; 312(不行) 合计只有5种可能性。,5,下面我们再给出顺序栈结构的基本操作:,(1)初始化栈 InitStack(S) (2)入栈 Push(S,item) (3)出栈 Pop(S,item) (4)获取栈顶元素内容 GetTop(S,item) (5)判断栈是否为空 StackEmpty(S),6,栈的顺序存储的定义栈的顺序存储结构是用一组连续的存储单元依次存放栈中的每个数据元素,并用起始端作为栈底。,类型定义如下所示: #define MAX 10 /栈的最大数据元素数目typed

4、ef struct stack char Data 1MAX; /存放栈中数据元素的存储单元int top; /栈顶指针 STACK;,7,基本操作算法(简化): 1.初始化栈S void InItStack(STACK *S) s-top= 0; /* s-top为栈顶指针,在顺序结构中既为数组下标*/,2. 入栈 void Push(STACK *S, DataType x ) if (S-top=MAX_STACK) exit(“Stack is full”);else S-Data +(S-top)=x; ,出栈,8,3.出栈 void Pop(STACK *S) if (StackE

5、mpty(S) exit(“Stack is empty”); return S-data (S-top); s-top-; ,4. 获取栈顶元素内容 void GetTop(STACK * S) if (StackEmpty(S) exit(“Stack is empty”);return S-dataS-top; ,9,5. 判断栈S是否为空int StackEmpty(STACK *S)if (S-top= 0) return TRUE;else FALSE;,结论:由于栈的插入和删除操作具有它的特殊性,所以用顺序存储结构表示的栈并不存在插入删除数据元素时需要移动的问题,但栈容量难以扩充

6、的弱点仍就没有摆脱。,10,3.1.3 线性表的链式存储(补充),结点定义: typedef struct node int data;struct node *next; stack; Stack top; /定义栈的栈顶指针,11,初始化栈S Void InitStack (STACK *S) top=NULL;,链栈各项基本操作的算法:,12,2. 入栈简化算法,void Push(STACK * S ,DataType x ) STACK*p=(NODE*) malloc (sizeof(NODE);P-data=x;p-next=top;top=p; ,13,2. 出栈简化算法,vo

7、id Pop(Stack *S) DataType x; stack *q;if (StackEmpty(top) exit(“Stack is empty”);else x=top-data;q=top;top=q-next; free(q) ,14,4. 获取栈顶元素内容void GetTop(STACK * S ) if (StackEmpty(S) exit(“Stack is empty”);else return top-data; 5. 判断栈S是否空 int StackEmpty(STACK *S) if (top=NULL) return TRUE;else FALSE; ,

8、15,3.1.4 栈的应用举例【举例1】将从键盘输入的字符序列逆置输出.比如,从键盘上输入:tset a si sihT;算法将输出:This is a test,16,【举例1】将从键盘输入的字符序列逆置输出,下面我们给出解决这个问题的完整算法。void ReverseRead( ) STACK *S; /定义一个栈结构Schar ch;InitStack(S); /初始化栈,17,while (ch=getchar()!=n) /从键盘输入字符,直到输入换行符为止push(S,ch); /将输入的每个字符入栈 while (!StackEmpty(S) /依次退栈并输出退出的字符pop(S

9、, ,18,课堂思考题!,一个双向栈是将两个栈用一个数组构成,它们的栈底分别设在数组的两端。当一个栈中元素的数目小于n/2时,另一个栈相应的可以大于n/2。试写出以数组高端为底的栈的入栈和出栈的算法。,19,分析:,这个栈的栈顶指针top2是按相反的方向移动的,因此算法有所不同:入栈时为:top2=top2-1出栈时为:top2=top2+1两个栈在进栈过程中防止溢出的条件是: top2=top1+1 。出栈过程中防止下溢出及判断空栈的条件分别为:top1=0,top2=(n+1),20,入栈算法,void push (ST, int n, top1, top2, G) if (top2=to

10、p1+1)printf(“溢出!n”);elsetop2=top2-1;STtop2=G; /*插入新元素*/ ,21,出栈算法:,void pop (ST, int n, top1, top2, x) if (top2=n+1)printf(“下溢出!n”);elsex=STtop2;top2=top2+1; ,同理可写出以数组低端为底的出入栈算法,22,队列的定义及特点 定义:队列是限定只能在表的一端进行插入,在表的另一端进行删除的线性表; 队尾(tail) 允许插入的一端; 队头(head)允许删除的一端; 队列特点:先进先出(FIFO);,3.2 队 列,23,顺序队列示意图,(队尾元

11、素),(队首元素),head, 空队列的特征?约定:,入队(尾部插入):datatail=e; tail+; 出队(头部删除):x=datahead; head+;,讨 论:,假溢出,有缺陷, 怎样实现入队和出队操作?,3.2 .1 顺序队列,head=tail,注意!为了方便操作可以把队尾指针指向最后一个元素的下一个空位,与课本不同.,typedef struct node Datatype datamax;int head, tail; NODE;,24,解决方案 队首固定,每次出队剩余元素向上移动浪费时间; 循环队列 基本思想:把队列设想成环形,让q0接在qM-1之后,若tail+1=M

12、,则令tail=0; 实现: 利用“模”运算; 入队:qtail=x; tail=(tail+1)%M; 出队:x=qhead; head=(head+1)%M; ( 注意,与课本不同,因为我们采用队列首尾指针不同,我们的设置更方便 ),存在问题设数组维数为M,则:当head=0,tail=M时,再有元素入队发生溢出真溢出当head0,tail=M时,再有元素入队发生溢出假溢出,25,tail,head,初始状态,队空:head=tail 队满:head=tail,解决方案: 1.另外设一个标志以区别队空、队满; 2.少用一个元素空间: 3采用记数器变量,记录元素总个数。队空条件:(q-hea

13、d=q-tail)&Q-count=0)队满条件:(q-head=q-tail)&Q-count=M),思考:队满、队空判定条件,26,循环队列各项基本操作算法: 初始化队列 判队空 判队满 入队 出队,27,(1)初始化队列Q void InitQueue( QUEUE *Q) Q-tail=0;Q-head=0;Q-count=0; ,循环队列各项操作简化算法(采用记数器变量)。,28,(2)判断队列Q是否为空 int QueueEmpty( Queue * Q) return Q-count=0; ,(3)判断队列Q是否为满 int QueueEmpty(Queue * Q) retur

14、n Q-count=QueueSize; ,29,(4)入队算法:,采用一个记数器的方法来判断对列空或满. 队空条件:(Q-head=Q-tail)&(Q-count=0) 队满条件: (Q-head=Q-tail)&(Q-count=QueueSize),Void Enqueue(Queue *Q, Data X ) if(Queue full(Q) Error(“overflow”); Q-count+; Q-data Q-tail=X; Q-tail=(Q-tail)+1)%QueueSize ,30,(5)出队算法:,Data Dequeue (cirQueue *Q) Data te

15、mp;if(QueueEmpty(Q) Error(“under flow”); Temp= Q- data Q-head; Q-count-; Q-head=(Q-head+1)%QueueSize,31,4)获取队头元素内容,void GetFront(QUEUE *Q) if (QueueEmpty(Q) exit (“Queue is empty.”);else return Q-dataQ-head; ,32,3.2.3链队列 结点定义,typedef struct node int data;struct node * next; NODE;,设队首、队尾指针head和tail,

16、head指向队首结点,tail指向队尾节点; (注意:与顺序队列不同),33,下面我们给出链式队列的基本操作算法:(1)初始化队列Q void InitQueue(Queue *Q)Q-head= Q-tail=null;,34,(2)入队算法 void EnQueue(QUEUE *Q, DataType x) Node * p=(Node *)malloc(sizeof(Node);p-data=x;p-next=NULL; If(QueueEmpty(Q)Q-head=Q-tail =p; /*如果队列为空*/ else (Q-tail)-next =p; /*如果队列不为空*/Q-ta

17、il =p; ,35,(3)出队算法 void DeQueue(QUEUE *Q) if (QueueEmpty(*Q) exit(ERROR); /下溢else p=Q-head;X=p-data;Q-head=p-next;if(Q-tail= =p) Q-tail=Null; /删除后队列为空free(p);return x ,p,36,(4)获取队头元素内容 void GetFront (QUEUE *Q) if (QueueEmpty(Q) exit(ERROR);else return=Q-head-data; ,(5)判断队列Q是否为空 int QueueEmpty(QUEUE

18、*Q) if (Q-head=NULL) return TRUE;else return FALSE; ,37,4队列的应用举例 【举例1】汽车加油站。随着城市里汽车数量的急速增长,汽车加油站也渐渐多了起来。通常汽车加油站的结构基本上是:入口和出口为单行道,加油车道可能有若干条。每辆车加油都要经过三段路程,第一段是在入口处排队等候进入加油车道;第二段是在加油车道排队等候加油;第三段是进入出口处排队等候离开。实际上,这三段都是队列结构.思考:若用算法模拟这个过程,就需要设置加油车道数加2个队列。,38,【举例2】CPU分时系统在一个带有多个终端的计算机系统中,同时有多个用户需要使用CPU运行各自

19、的应用程序,它们分别通过各自的终端向操作系统提出使用CPU的请求,操作系统通常按照每个请求在时间上的先后顺序,将它们排成一个队列,每次把CPU分配给当前队首的请求用户,即将该用户的应用程序投入运行,当该程序运行完毕或用完规定的时间片后,操作系统再将CPU分配给新的队首请求用户,这样即可以满足每个用户的请求,又可以使CPU正常工作。,39,例3.2对于循环顺序队列,试写出求队列长度的算法 。,解1:设队列的最大元素个数为n,设一个计数器,将其初始值设为0。从队首开始,沿着队列顺序搜索,每走过一个元素,计数器加1,直到队尾,则计数器的最终值即为队列的长度。 解2:利用队头指针与队尾指针也可求出队列

20、的长度: 当rf时,length=r-f; 当rf时,length=(r+n)-f。,40,算法一,int Que_Length (Queue,int f,r,n) int length,k;length=0;k=f;while (k!=r)length+;k=(k+1)%nreturn(length); ,41,算法2,int Que_lenrth(Queue,f,r,n) int length=0;if (r=f)length=r-f;elselength=(r+n)-f;return(length); ,42,本章小结,线性表、栈与队的异同点: 相同点:逻辑结构相同,都是线性的;都可以用

21、顺序存储或链表存储;栈和队列是两种特殊的线性表,即受限的线性表(只是对插入、删除运算加以限制)。 不同点:运算规则不同,线性表为随机存取,而栈是只允许在一端进行插入和删除运算,因而是后进先出表LIFO;队列是只允许在一端进行插入、另一端进行删除运算,因而是先进先出表FIFO。,43,习题与练习,一、基本知识题 1. 什么是线性表?线性表的主要运算有哪些? 2. 什么是栈?什么是队列?它们各自的特点是什么? 3. 线性表、栈、队列有什么异同? 4. 简述栈的入栈、出栈操作的过程。 5. 在什么情况下,才能使用栈、队列等数据结构?,44,二、算法设计题 1. 设有一n个元素的线性表,用一维数组An

22、表示。试设计一个算法,使此线性表元素的排队次序颠倒过来但仍存储于原数组中。2. 设一循环队列Queue,有头指针front,尾指针tail,另设一个内含元素个数的计数器,试写出相应的入队、出队算法?(并且思考如果只有头指针没有尾指针如何设计算法),45,Q:A是由N个元素构成的数组,颠倒其中的存放次序,即把A0中存放的数据与AN-1中存放的数据交换,把A1中存放的数据与AN-2中存放的数据交换,.,例一分析:颠倒数组元素存放次序,for(i=0;iN/2;i+) temp=Ai;Ai=AN-i-1;AN-i-1=temp; ,分析: 1. 总共需要进行N/2次的元素交换,可以用一个循环计数变量

23、i从0到N/2计数,进行相应的控制; 2. 交换的对象是第i下标的元素和第N-i-1下标的元素,即Ai与AN-i-1; 3. 以一个变量为中间过渡,交换两个数组元素的值。,46,例二 入队算法:,采用一个记数器的方法来判断对列空或满. 队空条件:(Q-front=Q-rear)&(Q-count=0) 队满条件:(Q-front=Q-rear)&(Q-count=QueueSize),Void Enqueue(cirQueue *Q,Data X ) if(Queue full(Q) Error(“overflow”); Q-count+; Q-data Q-rear=X; Q-rear=(Q-rear+1)%QueueSize ,47,例二 出队算法:,Data Dequeue (cirQueue *Q) Data temp;if(QueueEmpty(Q) Error(“under flow”); Temp=Q-dataQ-front; Q-count-; Q-front=(Q-front+1)%QueueSize ,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报