數(shù)據(jù)結(jié)構(gòu)(隊(duì)列)的應(yīng)用——Queue(隊(duì)列)和Deque(雙端隊(duì)列)

一、隊(duì)列的定義

隊(duì)列也是數(shù)據(jù)結(jié)構(gòu)的其中一種,和棧相反的是。隊(duì)列是只允許在一端進(jìn)行插入,在另一端進(jìn)行刪除的線性表。

插入的一端稱為隊(duì)尾,刪除的一端稱為隊(duì)頭。如下圖:

二、隊(duì)列的順序存儲結(jié)構(gòu)

基于數(shù)組實(shí)現(xiàn),底層結(jié)構(gòu)使用順序表進(jìn)行存儲數(shù)據(jù)。

使用順序表存儲有個缺點(diǎn):出隊(duì)的時(shí)間復(fù)雜度高O(n); 容易形成假溢出。

循環(huán)隊(duì)列:把隊(duì)列的頭尾相接的并且使用順序存儲結(jié)構(gòu)進(jìn)行數(shù)據(jù)存儲的隊(duì)列稱之為循環(huán)隊(duì)列。

三、隊(duì)列的鏈?zhǔn)酱鎯Y(jié)構(gòu)

隊(duì)列的鏈?zhǔn)酱鎯Y(jié)構(gòu),其實(shí)就是線性表的單鏈表,只不過它只能尾進(jìn)頭出而已。即只能找頭結(jié)點(diǎn)進(jìn)行刪除,在單鏈表的最后一個節(jié)點(diǎn)進(jìn)行刪除而已。

鏈?zhǔn)酱鎯Y(jié)構(gòu)的空隊(duì)列就是鏈表的頭指針和尾指針都指向同一個節(jié)點(diǎn),并且這個節(jié)點(diǎn)沒有數(shù)據(jù)域。如下圖:

四、隊(duì)列的變形——雙端隊(duì)列(實(shí)現(xiàn)Deque接口)

實(shí)現(xiàn)Deque接口的實(shí)現(xiàn)類都可當(dāng)做雙端隊(duì)列來使用,如LinkedList。

Deque是一種具有隊(duì)列和棧的性質(zhì)的數(shù)據(jù)結(jié)構(gòu)。雙端隊(duì)列中的元素可以從兩端彈出,也可以在兩端進(jìn)行插入;即可以在表的兩端進(jìn)行插入和刪除操作。

雙端隊(duì)列在我們也經(jīng)常使用到,如LinkedList(鏈表存儲結(jié)構(gòu))、ArrayDeque(順序表存儲結(jié)構(gòu))、LinkedBlockingDeque(阻塞式的雙端隊(duì)列)。

這其中LinkedBlockingDeque是線程安全的,因?yàn)樗诿看尾迦牒蛣h除上都加了鎖來控制。如果我們還想了解更多的線程安全的隊(duì)列,可以查看java并發(fā)包里面的許多實(shí)現(xiàn)類。

我們在這里就不分析源代碼了,只要看懂了順序表和鏈表的增刪改查操作,隊(duì)列的方法也基本一樣,只是加入了一些自己的東西。

五、優(yōu)先級隊(duì)列(PriorityQueue)

優(yōu)先級隊(duì)列和通常的棧和隊(duì)列一樣,只不過里面的每一個元素都有一個優(yōu)先級,我們在處理的時(shí)候首先處理優(yōu)先級最高的。如果兩個元素具有相同的優(yōu)先級,則按照他們插入到隊(duì)列中的先后順序進(jìn)行處理。

通過分析源代碼,我看到了優(yōu)先級隊(duì)列的思想:

它的插入和刪除操作其實(shí)就是在對一棵完全二叉樹進(jìn)行建堆操作。因?yàn)槭且豢猛耆鏄洌晕覀兛梢杂脭?shù)組(而不是鏈表)方式來實(shí)現(xiàn)。因?yàn)閷τ跀?shù)組實(shí)現(xiàn)的完全二叉樹,index為i的節(jié)點(diǎn),它的父節(jié)點(diǎn)的 index 是i/2,左子節(jié)點(diǎn)的index是i2,右子節(jié)點(diǎn)的index是i2+1。乘2和除2都是可以通過位移來實(shí)現(xiàn)的,效率上很好。而且通過保存元素個數(shù), 可以O(shè)(1)時(shí)間只找到處于樹的最未的那個元素。用數(shù)組來實(shí)現(xiàn)還有一個好處,就是不需要在數(shù)據(jù)結(jié)構(gòu)中再實(shí)現(xiàn)對父、子節(jié)點(diǎn)的指針存儲,這樣也省下了不少空間。

關(guān)于完全二叉樹的建堆操作,我們在之前的文章里面已經(jīng)詳細(xì)說明了,就是進(jìn)行堆排序的過程,所以我們的優(yōu)先級隊(duì)列(PriorityQueue)里的元素就是有序的。

優(yōu)先級隊(duì)列一般分最大優(yōu)先級隊(duì)列和最小優(yōu)先級隊(duì)列 ,這兩種優(yōu)先級隊(duì)列只是為了適應(yīng)不同場合的需要而進(jìn)行區(qū)分實(shí)現(xiàn),在算法上來講沒有什么本質(zhì)的不同。就是構(gòu)建最大堆和最小堆的過程。

優(yōu)先級隊(duì)里的應(yīng)用:MessageQueue、平常開發(fā)中有涉及到優(yōu)先級的集合都可以使用優(yōu)先級隊(duì)列。

如果要考慮線程安全,可以使用java并發(fā)包里的PriorityBlockingQueue,里面使用了鎖來保證高并發(fā)訪問時(shí)候的操作,但是一般Android代碼都用不到高并發(fā)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容