队列入门简介
線性結(jié)構(gòu)的兩種常見(jiàn)應(yīng)用之二隊(duì)列
定義:種可以實(shí)現(xiàn)“先進(jìn)先出”的存儲(chǔ)結(jié)構(gòu)
分類(lèi):鏈?zhǔn)疥?duì)列(鏈表實(shí)現(xiàn))、靜態(tài)隊(duì)列(數(shù)組實(shí)現(xiàn))
?
隊(duì)列(常用數(shù)據(jù)結(jié)構(gòu)之一)
隊(duì)列是一種特殊的線性表,特殊之處在于它只允許在表的前端(front)進(jìn)行刪除操作,而在表的后端(rear)進(jìn)行插入操作,和棧一樣,隊(duì)列是一種操作受限制的線性表。進(jìn)行插入操作的端稱(chēng)為隊(duì)尾,進(jìn)行刪除操作的端稱(chēng)為隊(duì)頭。
簡(jiǎn)介
隊(duì)列是一種特殊的線性表,特殊之處在于它只允許在表的前端(front)進(jìn)行刪除操作,而在表的后端(rear)進(jìn)行插入操作,和棧一樣,隊(duì)列是一種操作受限制的線性表。進(jìn)行插入操作的端稱(chēng)為隊(duì)尾,進(jìn)行刪除操作的端稱(chēng)為隊(duì)頭。隊(duì)列中沒(méi)有元素時(shí),稱(chēng)為空隊(duì)列。
隊(duì)列的數(shù)據(jù)元素又稱(chēng)為隊(duì)列元素。在隊(duì)列中插入一個(gè)隊(duì)列元素稱(chēng)為入隊(duì),從隊(duì)列中刪除一個(gè)隊(duì)列元素稱(chēng)為出隊(duì)。因?yàn)殛?duì)列只允許在一端插入,在另一端刪除,所以只有最早進(jìn)入隊(duì)列的元素才能最先從隊(duì)列中刪除,故隊(duì)列又稱(chēng)為先進(jìn)先出(FIFO—first in first out)線性表。
順序隊(duì)列
建立順序隊(duì)列結(jié)構(gòu)必須為其靜態(tài)分配或動(dòng)態(tài)申請(qǐng)一片連續(xù)的存儲(chǔ)空間,并設(shè)置兩個(gè)指針進(jìn)行管理。一個(gè)是隊(duì)頭指針front,它指向隊(duì)頭元素;另一個(gè)是隊(duì)尾指針rear,它指向下一個(gè)入隊(duì)元素的存儲(chǔ)位置,如圖所示
每次在隊(duì)尾插入一個(gè)元素是,rear增1;每次在隊(duì)頭刪除一個(gè)元素時(shí),front增1。隨著插入和刪除操作的進(jìn)行,隊(duì)列元素的個(gè)數(shù)不斷變化,隊(duì)列所占的存儲(chǔ)空間也在為隊(duì)列結(jié)構(gòu)所分配的連續(xù)空間中移動(dòng)。當(dāng)front=rear時(shí),隊(duì)列中沒(méi)有任何元素,稱(chēng)為空隊(duì)列。當(dāng)rear增加到指向分配的連續(xù)空間之外時(shí),隊(duì)列無(wú)法再插入新元素,但這時(shí)往往還有大量可用空間未被占用,這些空間是已經(jīng)出隊(duì)的隊(duì)列元素曾經(jīng)占用過(guò)得存儲(chǔ)單元。
順序隊(duì)列中的溢出現(xiàn)象:
(1) "下溢"現(xiàn)象:當(dāng)隊(duì)列為空時(shí),做出隊(duì)運(yùn)算產(chǎn)生的溢出現(xiàn)象。“下溢”是正常現(xiàn)象,常用作程序控制轉(zhuǎn)移的條件。
(2)"真上溢"現(xiàn)象:當(dāng)隊(duì)列滿(mǎn)時(shí),做進(jìn)棧運(yùn)算產(chǎn)生空間溢出的現(xiàn)象。“真上溢”是一種出錯(cuò)狀態(tài),應(yīng)設(shè)法避免。
(3)"假上溢"現(xiàn)象:由于入隊(duì)和出隊(duì)操作中,頭尾指針只增加不減小,致使被刪元素的空間永遠(yuǎn)無(wú)法重新利用。當(dāng)隊(duì)列中實(shí)際的元素個(gè)數(shù)遠(yuǎn)遠(yuǎn)小于向量空間的規(guī)模時(shí),也可能由于尾指針已超越向量空間的上界而不能做入隊(duì)操作。該現(xiàn)象稱(chēng)為"假上溢"現(xiàn)象。
循環(huán)隊(duì)列
在實(shí)際使用隊(duì)列時(shí),為了使隊(duì)列空間能重復(fù)使用,往往對(duì)隊(duì)列的使用方法稍加改進(jìn):無(wú)論插入或刪除,一旦rear指針增1或front指針增1 時(shí)超出了所分配的隊(duì)列空間,就讓它指向這片連續(xù)空間的起始位置。自己真從MaxSize-1增1變到0,可用取余運(yùn)算rear%MaxSize和front%MaxSize來(lái)實(shí)現(xiàn)。這實(shí)際上是把隊(duì)列空間想象成一個(gè)環(huán)形空間,環(huán)形空間中的存儲(chǔ)單元循環(huán)使用,用這種方法管理的隊(duì)列也就稱(chēng)為循環(huán)隊(duì)列。除了一些簡(jiǎn)單應(yīng)用之外,真正實(shí)用的隊(duì)列是循環(huán)隊(duì)列。?[2]?
在循環(huán)隊(duì)列中,當(dāng)隊(duì)列為空時(shí),有front=rear,而當(dāng)所有隊(duì)列空間全占滿(mǎn)時(shí),也有front=rear。為了區(qū)別這兩種情況,規(guī)定循環(huán)隊(duì)列最多只能有MaxSize-1個(gè)隊(duì)列元素,當(dāng)循環(huán)隊(duì)列中只剩下一個(gè)空存儲(chǔ)單元時(shí),隊(duì)列就已經(jīng)滿(mǎn)了。因此,隊(duì)列判空的條件時(shí)front=rear,而隊(duì)列判滿(mǎn)的條件時(shí)front=(rear+1)%MaxSize。隊(duì)空和隊(duì)滿(mǎn)的情況如圖:
隊(duì)列的數(shù)組實(shí)現(xiàn)
隊(duì)列可以用數(shù)組Q[1…m]來(lái)存儲(chǔ),數(shù)組的上界m即是隊(duì)列所容許的最大容量。在隊(duì)列的運(yùn)算中需設(shè)兩個(gè)指針:head,隊(duì)頭指針,指向?qū)嶋H隊(duì)頭元素;tail,隊(duì)尾指針,指向?qū)嶋H隊(duì)尾元素的下一個(gè)位置。一般情況下,兩個(gè)指針的初值設(shè)為0,這時(shí)隊(duì)列為空,沒(méi)有元素。數(shù)組定義Q[1…10]。Q(i) i=3,4,5,6,7,8。頭指針head=2,尾指針tail=8。隊(duì)列中擁有的元素個(gè)數(shù)為:L=tail-head。現(xiàn)要讓排頭的元素出隊(duì),則需將頭指針加1。即head=head+1這時(shí)頭指針向上移動(dòng)一個(gè)位置,指向Q(3),表示Q(3)已出隊(duì)。如果想讓一個(gè)新元素入隊(duì),則需尾指針向上移動(dòng)一個(gè)位置。即tail=tail+1這時(shí)Q(9)入隊(duì)。當(dāng)隊(duì)尾已經(jīng)處理在最上面時(shí),即tail=10,如果還要執(zhí)行入隊(duì)操作,則要發(fā)生"上溢",但實(shí)際上隊(duì)列中還有三個(gè)空位置,所以這種溢出稱(chēng)為"假溢出"。
克服假溢出的方法有兩種。一種是將隊(duì)列中的所有元素均向低地址區(qū)移動(dòng),顯然這種方法是很浪費(fèi)時(shí)間的;另一種方法是將數(shù)組存儲(chǔ)區(qū)看成是一個(gè)首尾相接的環(huán)形區(qū)域。當(dāng)存放到n地址后,下一個(gè)地址就"翻轉(zhuǎn)"為1。在結(jié)構(gòu)上采用這種技巧來(lái)存儲(chǔ)的隊(duì)列稱(chēng)為循環(huán)隊(duì)列。
隊(duì)列和棧一樣只允許在斷點(diǎn)處插入和刪除元素。
循環(huán)隊(duì)的入隊(duì)算法如下:
1、tail=tail+1;
2、若tail=n+1,則tail=1;
3、若head=tail,即尾指針與頭指針重合了,表示元素已裝滿(mǎn)隊(duì)列,則作上溢出錯(cuò)處理;
4、否則,Q(tail)=X,結(jié)束(X為新入出元素)。
隊(duì)列和棧一樣,有著非常廣泛的應(yīng)用。
注意:(1)有時(shí)候隊(duì)列中還會(huì)設(shè)置表頭結(jié)點(diǎn),就是在隊(duì)頭的前面還有一個(gè)結(jié)點(diǎn),這個(gè)結(jié)點(diǎn)的數(shù)據(jù)域?yàn)榭?#xff0c;但是指針域指向隊(duì)頭元素。
(2)另外,上面的計(jì)算還可以利用下面給出的公式cq.rear=(cq.front+1)/max;
當(dāng)有表頭結(jié)點(diǎn)時(shí),公式變?yōu)閏q.rear=(cq.front+1)/(max+1)。
隊(duì)列的鏈表實(shí)現(xiàn)
在隊(duì)列的形成過(guò)程中,可以利用線性鏈表的原理,來(lái)生成一個(gè)隊(duì)列。
基于鏈表的隊(duì)列,要?jiǎng)討B(tài)創(chuàng)建和刪除節(jié)點(diǎn),效率較低,但是可以動(dòng)態(tài)增長(zhǎng)。
隊(duì)列采用的FIFO(first in first out),新元素(等待進(jìn)入隊(duì)列的元素)總是被插入到鏈表的尾部,而讀取的時(shí)候總是從鏈表的頭部開(kāi)始讀取。每次讀取一個(gè)元素,釋放一個(gè)元素。所謂的動(dòng)態(tài)創(chuàng)建,動(dòng)態(tài)釋放。因而也不存在溢出等問(wèn)題。由于鏈表由結(jié)構(gòu)體間接而成,遍歷也方便。
隊(duì)列的基本運(yùn)算
(1)初始化隊(duì)列:Init_Queue(q) ,初始條件:隊(duì)q 不存在。操作結(jié)果:構(gòu)造了一個(gè)空隊(duì);
(2)入隊(duì)操作: In_Queue(q,x),初始條件: 隊(duì)q 存在。操作結(jié)果: 對(duì)已存在的隊(duì)列q,插入一個(gè)元素x 到隊(duì)尾,隊(duì)發(fā)生變化;
(3)出隊(duì)操作: Out_Queue(q,x),初始條件: 隊(duì)q 存在且非空,操作結(jié)果: 刪除隊(duì)首元素,并返回其值,隊(duì)發(fā)生變化;
(4)讀隊(duì)頭元素:Front_Queue(q,x),初始條件: 隊(duì)q 存在且非空,操作結(jié)果: 讀隊(duì)頭元素,并返回其值,隊(duì)不變;
(5)判隊(duì)空操作:Empty_Queue(q),初始條件: 隊(duì)q 存在,操作結(jié)果: 若q 為空隊(duì)則返回為1,否則返回為0。?[3]?
| 操作 | 類(lèi)型 | 作用 | 返回值 | 例子 |
| length(s) | 函數(shù) | 求字符串s的長(zhǎng)度 | 整型 | s:='123456789'; l:=length(s);{l的值為9} |
| copy(s,w,k) | 函數(shù) | 復(fù)制s中從w開(kāi)始的k位 | 字符串 | s:='123456789'; s1:=copy(s,3,5);{s1的值是'34567'} |
| val(s,k,code) | 過(guò)程 | 將字符串s轉(zhuǎn)為數(shù)值,存在k中;code是錯(cuò)誤代碼 | var s:string;k,code:integer; begin s:='1234'; val(s,k,code); write(k);{k=1234} | |
| str(i,s) | 過(guò)程 | 將數(shù)值i轉(zhuǎn)為字符串s | i:=1234; str(i,s); write(s);{s='1234'} | |
| Delete(s,w,k) | 過(guò)程 | 在s中刪除從第w位開(kāi)始的k個(gè)字符 | s := 'Honest Abe Lincoln'; Delete(s,8,4); Writeln(s); { 'Honest Lincoln' } | |
| Insert(s1, S, w) | 過(guò)程 | 將s1插到s中第w位 | S := 'Honest Lincoln'; Insert('Abe ', S, 8); { 'Honest Abe Lincoln' } | |
| Pos(c, S) | 函數(shù) | 求字符c在s中的位置 | 整型 | S := ' 123.5'; i :=Pos(' ', S);{i的值為1} |
| + | 運(yùn)算符 | 將兩個(gè)字符串連接起來(lái) | s1:='1234'; s2:='5678'; s:=s1+s2;{'12345678'} |
在STL中,對(duì)隊(duì)列的使用很是較完美
下面給出循環(huán)隊(duì)列的運(yùn)算算法:
(1)將循環(huán)隊(duì)列置為空
//將隊(duì)列初始化 SeQueue::SeQueue(){ front=0;rear=0;cout<<"init!"<<endl; }(2)判斷循環(huán)隊(duì)列是否為空
int SeQueue::Empty(){ if(rear==front){return(1);}else{ return(0);} }(3)在循環(huán)隊(duì)列中插入新的元素x?
void SeQueue::AddQ(ElemType x){ if((rear+1) % MAXSIZE==front) {cout<<" QUEUE IS FULL! "<<endl;}else{ rear=(rear+1) % MAXSIZE;elem[rear]=x;cout<<" OK!";} }(4)刪除隊(duì)列中隊(duì)首元素
ElemType SeQueue::DelQ(){ if(front==rear){ cout<<" QUEUE IS EMPTY! "<<endl; return -1;}else{ front=(front+1) % MAXSIZE;return(elem[front]);} }(5)取隊(duì)列中的隊(duì)首元素?
ElemType SeQueue::Front(){ ElemType x;if(front== rear){cout<<"QUEUE IS EMPTY "<<endl;}else{ x= elem[(front+1)%MAXSIZE];return (x);} }?
?
?
總結(jié)
- 上一篇: Java抽象类的概念和使用
- 下一篇: java泛型通配符和类型参数的范围