链式队列输入.docx
《链式队列输入.docx》由会员分享,可在线阅读,更多相关《链式队列输入.docx(19页珍藏版)》请在冰豆网上搜索。
链式队列输入链式队列输入队列的基本操作及应用【教学目的】
(1)掌握队列的定义及队列的存储结构(顺序存储、链式存储);
(2)掌握队列的基本操作运算:
建队列、插入、删除、队列空等;(3)掌握循环队列的概念及运算;(4)能够利用队列解决一些实际问题:
宽度优先搜索算法【教学重点】综合运用队列结构解决实际问题。
【教学过程】一、队列的定义前面所讲的栈是一种后进先出的数据结构,而在实际问题中还经常使用一种“先进先出”(FIFOFirstInFirstOut)的数据结构:
即插入在表一端进行,而删除在表的另一端进行,我们将这种数据结构称为队或队列,把允许插入的一端叫队尾(rear),把允许删除的一端叫队头(front)。
如图1所示是一个有5个元素的队列。
入队的顺序依次为a1、a2、a3、a4、a5,出队时的顺序将依然是a1、a2、a3、a4、a5。
显然,队列也是一种运算受限制的线性表,所以又叫先进先出表。
在日常生活中队列的例子很多,如排队买东西,排头的买完后走掉,新来的排在队尾。
二、基本术语
(1)队空:
当队列中没有元素时称为空队列;
(2)队满:
当队列中单元全部被占用;(3)进队:
向队列中插入新元素;(4)出队:
从队列中删除元素;(5)(假)溢出:
队尾指针指向最后一个位置,但队头前面仍有空闲的单元可被利用。
三、队列操作示意图front=rear=1front=1rear=2front=5rear=8front=5rear=9(a)空队(b)有3个元素(c)一般情况(d)假溢出现象四、队列的存储结构与线性表、栈类似,队列也有顺序存储和链式存储两种存储方法。
1顺序存储顺序存储的队列称为顺序队列。
因为队列的队头和队尾都是活动的,因此,除了队列的数据区外还有队头、队尾两个指针。
顺序队列的类型定义如下:
typequeue=recorddata:
array0.maxsize-1ofelemtypefront,rear:
integer;end;front指向队列中第一个元素的前一个单元;rear指向队列中最后一个元素的单元。
2链式存储链式存储的队列称为链队。
和链栈类似,用单链表来实现链队,根据队的FIFO原则,为了操作上的方便,我们分别需要一个头指针和尾指针,如图2所示。
五、队列的基本运算
(1)初始化:
设定Q为一空队列:
procedureiniqueue(varQ:
queue);beginQ.front:
=-1;Q.rear:
=-1;end;
(2)判队列空:
若队列Q为空,则返回值true,否则返回值false:
functionqempty(Q:
queue):
Boolean;beginqempty:
=(Q.front=Q.rear)end;(3)判队满:
若队列满,则返回值true,否则返回值false:
functionqfull(Q:
queue):
Boolean;beginQfull:
=(Q.rearmaxsize-1);end;(4)元素进队:
若队列Q不满时,把元素X插入到队列Q的队尾,否则返回信息“Overflow”:
procedureinqueue(varQ:
queue;X:
elemtype);beginifqfull(Q)thenwriteln(Overflow)elsebeginQ.rear:
=Q.rear+1;Q.dataQ.rear:
=X;endend;(5)元素出队:
若队列Q不空,则把队头元素删除并返回值给X,否则输出信息“Underflow”:
proceduredelqueue(varQ:
queue;varX:
elemtype);beginifqempty(Q)thenwriteln(Underflow)elsebeginQ.front:
=Q.front+1;X:
=Q.dataQ.front;end;end;(6)取队头元素:
若队列不空,返回队头元素的值,否则返回信息“Underflow”:
functiongethead(Q:
queue):
elemtype;beginifqempty(Q)thenwriteln(Underflow)elsegethead:
=Q.dataQ.front+1;end;六、循环队列所谓循环队列,就是将队列存储空间的最后一个位置绕到第一个位置,形成逻辑上的环状空间,供队列循环使用,循环队列的定义如队列。
当存储空间的最后一个位置已被使用而要进行入队运算时,只要存储空间第一个位置空闲,便可将元素加入到第一个位置,即将存储空间的第一个位置作为队尾。
采用首尾相接的循环队列结构后,可以有效地解决假溢出的问题,避免数据元素的移动。
七、循环队列的基本运算
(1)初始化:
设定Q为一空队列:
procedureiniqueue(varQ:
queue);beginQ.front:
=0;Q.rear:
=0;end;
(2)判队列空:
若队列Q为空,则返回值true,否则返回值false:
functionqempty(Q:
queue):
Boolean;beginqempty:
=(Q.front=Q.rear)end;(3)判队满:
若队列满,则返回值true,否则返回值false:
functionqfull(Q:
queue):
Boolean;beginqfull:
=(Q.rear+1)modmaxsize=Q.front);end;(4)元素进队:
若队列Q不满时,把元素X插入到队列Q的队尾,否则返回信息“Overflow”:
procedureinqueue(varQ:
queue;X:
elemtype);beginifqfull(Q)thenwriteln(Overflow)elsebeginQ.rear:
=(Q.rear+1)modmaxsize;Q.dataQ.rear:
=X;endend;(5)元素出队:
若队列Q不空,则把队头元素删除并返回值给X,否则输出信息“Underflow”:
proceduredelqueue(varQ:
queue;varX:
elemtype);beginifqempty(Q)thenwriteln(Underflow)elsebeginQ.front:
=(Q.front+1)modmaxsize;X:
=Q.dataQ.front;end;end;(6)取队头元素:
若队列不空,返回队头元素的值,否则返回信息“Underflow”:
functiongethead(Q:
queue):
elemtype;beginifqempty(Q)thenwriteln(Underflow)elsegethead:
=Q.data(Q.front+1)modmaxsize;end;八、队列的应用队列在计算机科学领域中所起的作用:
1、解决主机与外部设备之间速度不匹配的问题(如:
主机与打印机,设置一个打印数据缓冲区);2、解决由多用户引起的资源竞争问题(如:
CPU资源的竞争,操作系统按照每个请求的先后顺序,排成一个队列)。
九、典型例题例题1:
1995年高中组基础题第4题,从入口
(1)到出口(17)的可行路线图中,数字标号表示关卡:
现将上面的路线图,按记录结构存储如下:
请设计一种能从存储数据中求出从入口到出口经过最少关卡路径的算法。
【问题分析与答案】该题是一个路径搜索问题,根据图示,从入口
(1)到出口(17)可以有多种途径,其中最短的路径只有一条,那么如何找最短路径是问题的关键;根据题意,用一维数组存储各关卡号(设NO),用另一个数组存储访问到某关卡号的前趋卡号所在数组单元下标(设PRE);由于本题是一个典型的图的遍历问题,此题采用的是图的广度优先遍历算法,并利用队列的方式存储顶点之间的联系。
即访问一个点,将其后继结点入队,并存储它的前趋结点所在单元下标,直到最后从(17)点出口;从最后出口的关卡号(17)开始回访它的前趋卡号,则回返的搜索路径便是最短路径(跳过许多不必要搜索的关卡);从列表中可以看出出口关卡号(17)的被访问路径最短的是:
(17)(16)(19)(18)
(1)开始根据题意,要求从存储数据中写出从入口到出口的最少关卡路径的算法是:
从队列的最后一个关卡号开始,依次回访它的前驱顶点,所得到的路径即为最短路径。
算法如下:
i:
=1;whilenoi17doi:
=i+1repeatwrite(,noi,);write(-);i:
=prei;untili=0;例题2:
有10升油在10升的容器中,另有两个7升和3升的空容器,现要求用这三个容器倒油,使得最后在10升和7升的容器中各有5升油。
【算法分析】提示:
三个容器可以看作三个变量C10,C7,C3,每次倒油的可能性只有如下六种情况:
C10向C7倒油C10向C3倒油C7向C10倒油C7向C3倒油C3向C10倒油C3向C7倒油
(1)从一个容器的状态(三个容器中油的容量)看,虽然有可能经过上述六种倒油的方法产生六种容器状态,但实际上这六种新产生的容器状态,许多是已经出现过的状态。
例如初始状态(10,0,0)表示C10=10,C7=0,C3=0,经过上述六种倒油方法只能产生出两种新的容器状态(3,7,0),表示C10向C7倒油的结果和(7,0,3),表示C10向C3倒油的结果。
如果再增加应该表示新容器状态是由什么状态产生的指示pre,那么用这三个容器倒油的过程就可以用队列的方法来实现了。
(2)队列可以理解为一个数组,数组元素是如下记录:
RECORDC10,C7,C3,pre:
integer;END;数组下标为容器状态号。
下面是倒油过程的队列图示:
012345678910073re01234567当倒油产生出第19个容器状态时已达到了题解的目的。
这时只要根据pre中的状态号17可以回溯到第17个容器状态的pre值为15,依次可再获得13,11,9,7,5,2,1容器状态号,从而即可得到本题的倒油过程(共倒9次),而且是最少的倒油次数。
注意,从一个容器中向另一个容器中倒油,人操作是很直观的,对编程来说则必须考虑:
1)有没有油可倒?
2)究竟倒多少?
可能要全部倒入另一容器,也可能只要倒一部分另一容器已经满了。
队列元素说明了100个,是因为10升容器最多有010种状态,7升容器最多有07种状态,3升容器最多有03种状态,全部可能的状态为11*8*4=352种,但油的总量为10,因此352种可能状态中大部分是不存在的。
变量fp,rp在程序中用作队列的头指针和尾指针,flag在程序中标识是否已倒出了需要的容器状态(C10=5,C7=5)例题3:
迷宫问题下图是一个简单的迷宫迷宫图中阴影部分是不通的路径,处于迷宫中的每个位置都可以向8个方向探索着按可行路径前进。
假设出口位置在最右下角(6,8),入口在最左上角(1,1),试问能否设计出寻找一个从入口到出口的最短路径的算法呢?
图中的(1,1)(2,2)(3,3)(3,4)(4,5)(4,6)(5,7)(6,8)便是所求的一个这种路径。
【算法分析】为了设计求走迷宫的路径,首先要对迷宫进行描述,一种很自然的想法是把迷宫变为0,1值的二维数组,对上例而言可化为:
12345678101110111210101010301001111401110011510011000601100110探索路径的选择可描述为:
这样一来,迷宫中每个位置可探索的情况就分为:
只有三个探索方向的位置:
如(1,1);探索方向只有(1,2),(2,2)和(2,1);有五个探索方向的位置:
如(3,1);探索方向有(3,2),(4,2),(4,1),(2,1),(2,2);有八个探索方向的位置:
如(3,2);探索方向有(3,3),(4,3),(4,2),(4,1),(3,1),(2,1),(2,2),(2,3);能否不分情况统一按八种情况探索前进的路径呢?
只要把原始迷宫数据修正如下即可达到目的(外加一圈不通的围墙);01234567890111111111111011101111211010101013101001111141011100111511001100016101100110171111111111Mg:
array0.m+1,0.n+1ofinteger;探索方向可用x,y的增量组成数组:
xy10121131041-150-16-1-17-108-11Zl:
array1.8,1.2of1.1第二个要解决的问题应当考虑探索前进路径时如何把探索的踪迹记录下来,记录的踪迹一般应包括来处和当前位置,现设计如下顺序队列来完成探索路径的踪迹:
typesqtype=array1.rofrecordx,y:
integer;当前坐标pre:
0.r;前趋位置end;这里的r一般=mn,即迷宫的最大空位数目varsq:
sqtype;例如:
从(1,1)入口进入到达(3,3),往下探索时队列sq的情况:
123456x123332y123144pre012233frontrear注意,前趋采用了仅登记前趋在队列中的序号(前趋是由front指针指示的数据元素);为了防止被探索过的踪迹被重复探索,被探索到的可通行路径需在迷宫中做上标记,这里采用在迷宫数据中将0换成-1的方法实现,这样在走出迷宫时可以再把迷宫数据还原为原来的样子。
例如上例,探索到位置(3,3)的迷宫数据为:
11111111111-11110111111-11-1101011-11-1-1111111011100111110011000110110011011111111111最后根据队列sq中的存储信息和指针位置,即可链接成从迷宫入口到出口的最短路径。
就上例而言,sq队列的最后情况为:
1234567891011121314151617181920X12333244154525656656Y12314415526663175488Pre012233456788910101112141616出发点无frontrear前趋当rear指针指示的数据元素已到达出口(6,8)时,根据rear所据元素的前趋序号即可获得所要的走迷宫的最短路径(回溯)。
如果变更增量数组中八个数据元素的顺序,队列中存储的路径就可能不相同,最后可能回溯出不同的最短路径来。
例题4:
产生数(2002年NOIP普及组第3题)给出一个整数n(n=2000)和k个变换规则(k15)。
规则:
1个数字可以变换成另1个数字;规则中,右边的数字不能为零。
例如:
n=234,k=2规则为2536上面的整数234经过变换后可能产生出的整数为(包括原数)234534264564共4种不同的产生数求经过任意次的变换(0次或多次),能产生出多少个不同的整数。
仅要求输出不同整数个数。
输入:
键盘输入,格式为nkx1y1x2y2xnyn输出:
屏幕输出,格式为一个整数(满足条件的整数个数)。
输入输出样例输入:
23422536输出:
4【问题分析】本题考察了同学们三方面的能力:
数的表示,如数如何表示,如何处理;转换规则如何表示;队列的应用,包括入队、出队以及队的查找。
注意点:
数只能以字符串的形式输入,为了计算方便,经过类型转换存入整型数组中;对数的比较也很困难,只能逐位比较,处理时用一个队列q,开始时队列q中只有n。
【数据结构】str:
string;输入开始的数y,y1:
array1.4of0.9;工作单元q:
array1.2000,1.30of0.9;队列,设长度2000front,rear:
integer;存入和取出指针p:
array1.20,1.2of0.9;存储变换规则,即pi,1pi,2【算法流程】front:
=1;rear:
=1;whilefrontnext=NULL;return(L);voidInsLNode(LinkListL,ElemTypex)LinkLists,p;s=(LinkList)malloc(sizeof(LNode);s-datax;p=L;while(p-next)p=p-next;s-next=NULL;p-next=s;voidAddPolyn(LinkListpa,LinkListpb)LinkListha,hb,qa,qb;floatsum;inta,b;ha=pa;hb=pb;qa=ha-next;qb=hb-next;while(qa&qb)a=qa-data.expn;b=qb-data.expn;if(aha=qa;qa=qa-next;if(a=b)sum=qa-data.coef+qb-data.coef;if(sum!
=0)qa-data.coef=sum;ha=qa;qa=qa-next;hb-next=qb-next;free(qb);qb=hb-next;elseha-next=qa-next;free(qa);qa=ha-next;hb-next=qb-next;free(qb);qb=hb-next;if(ab)hb-next=qb-next;qb-next=ha-next;ha-next=qb;ha=qb;free(qb);qb=hb-next;if(qb)ha-next=qb;free(hb);voidInvert(LinkListL)LinkListp,q,r;p=L-next;q=p-next;while(q!
=NULL)r=q-next;q-next=p;p=q;q=r;L-next-next=NULL;L-next=p;voidPrint(LinkListL)LinkListp;p=L-next;while(p-next)printf(%fx%d+,p-data.coef,p-data.expn);p=p-next;printf(%fx%d,p-data.coef,p-data.expn);voidmain()LinkListLa,Lb;ElemTypec;inta,i,b;La=InitList();Lb=InitList();printf(输入La的项数:
);scanf(%d,&a);for(i=0;iA;I+)printf(输入La第%d项系数:
i+1);scanf(%f,&c.coef);printf(输入La第%d项指数:
i+1);scanf(%d,&c.expn);InsLNode(La,c);printf(输入Lb的项数:
);scanf(%d,&a);for(i=0;iA;I+)printf(输入Lb第%d项系数:
i+1);scanf(%f,&c.coef);printf(输入Lb第%d项指数:
i+1);scanf(%d,&c.expn);InsLNode(Lb,c);printf(La为);printf(n);Print(La);printf(n);printf(Lb为);printf(n);Print(Lb);printf(n);printf(多项式和为);printf(n);AddPolyn(La,Lb);Invert(La);Print(La);