一、隊(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ā)。