队列判空_三分钟基础:什么是队列?
作者 |? 小鹿
來源 |? 小鹿動畫學編程
寫在前邊
像線程池、異步隊列、消息隊列等有限的資源容器中,往往存儲大量的任務事件,這些大量的任務事件需要進行有條理的進行任務分發以及各種情況處理,為了能夠使得資源容器的正常運行,不得不使用一定的容器結構設計和策略,那么這些結構和策略如何實現的呢?
那小鹿不買官司了,就是用我們今天即將學到的數據結構“隊列”。雖然我們初學者實際中接觸的少,但是它的實際用途廣著呢,學好這部分是非常關鍵的。
思維導圖
1
什么是隊列?
何為隊列?顧名思義,排隊就是一個很好的例子。如果我們餐廳刷卡買飯,學生依次排隊,已購買完飯的在隊頭走了,剛來的同學就要排在隊尾后邊排隊。而不能直接在排好隊中插隊,這樣也壞了排隊這種“先來先去”規矩。
2
隊列的特點?
棧有出棧和入棧兩種,隊列也有入隊和出隊兩種操作,只不過是棧是先來后走,隊列則相反,先來先走。
正是因為隊列這種特點,使得它在一些有限的資源容器中的到廣泛的應用,比如線程池、資源池、消息隊列等。
3
如何實現隊列?
隊列和棧一樣,也有兩種實現方式,一種是順序隊列,一種是鏈式隊列。但是我們之前的文章中說過,無論是順序還是鏈式,都是由數組和鏈表演化而來,只不過是操作上進行了改進。
1、順序隊列
對于上邊的數組順序隊列,不知道大家有沒有發現一個問題就是,如果我一直的出隊、入隊會出現下邊這樣一種情況。
此時隊列再入隊,但是隊尾已滿,但是我們看到的明明隊頭還有空間的,如果此時擴大容量不就相當于浪費空間嗎?
那還有一個方法就是,每入隊一個元素,整體數據就往前移動一個空間,你可能會說,這樣操作起來是不是很費勁,而且效率不高,是的,這樣的確效率不高。
如果我們稍微改進一下,如果隊尾有空間,我們就讓元素一直入隊,直到隊尾沒有空間位置,然后進行整體進行一次搬移,這樣優化了入隊的效率。將這一次性進行大量搬移數據平均到每次上,平均時間復雜度還是 O(1)。
2、鏈式隊列
鏈式隊列是以鏈表組成的,它的優點就是可以無限的進行入隊,不用動態擴容。
4
隊列的種類?
4.1 循環隊列
循環隊列,顧名思義,將一般的隊列進行頭尾相接,形成一個圓,聲明兩個指針,一個帶邊隊頭,一個代表隊尾,入隊和出隊的時候,直接操作對應的指針即可。
但是為什么會出現循環隊列呢?是否還記得我們上邊所述,普通的隊列需要進行大量數據搬移,而循環隊列則沒有這個缺點。
但是循環隊列有一個比較重要的點就是判空和判斷是否已滿。
如上圖所示,判空的條件很簡單,頭指針等于尾指針的時候,此時循環隊列為空。
循環隊列滿的時候,我們要發現其上邊的規律得出隊滿的條件,(尾指針 + 1)% n = 頭指針。此時的循環隊列會浪費一個空間。
上邊我們涉及到的隊列是從結構上進行來區分的,下面我們就從實際開發功能上進行劃分。其實就是對一些功能的需求對隊列操作上設定了一定的要求。
4.2 阻塞隊列
我們拿一個例子入手,如果你學習過Android開發,里邊有個MessageQueue消息隊列。如果沒有接觸過,也沒關系,可以將其理解為放置消息的一個容器。
這個容器主要存放系統給它分發的任務消息,然后當有線程來分配任務的時候,此時該容器,也就是消息隊列就會在隊列中拿出任務然后分發給線程去執行。但是有這樣兩種情況需要進行設計。
第一種情況就是當任務消息隊列沒有任務的時候,此時線程來拿任務,該怎么辦?
第二種情況就是,當沒有空閑線程來取任務,此時任務消息隊列已經滿了,系統再分發新的任務時,又該如何處理呢?
那我相對于這兩種情況,就用到我們的阻塞隊列。當遇到第一種情況時,此時消息隊列為空,在隊頭拿數據的時候會被阻塞,也就是被阻止了,因為隊列中為空,只有等到隊列中有新的數據時,線程才可以拿去新的任務。
當遇到第二種情況,如果隊列已經滿了,此時沒有空余線程來取任務,此時隊列也被阻塞了,當有空余線程來獲取任務的時候,任務隊列才可取數據。
其實上邊的設計思路和我們所涉及到的設計模式中的 “發布-訂閱者模式”相同。
生產者代表往消息隊列中增加數據,消費者代表線程不斷的拿去任務去執行,我們可以通過調節生產著和消費者的數量來調節隊列匯總的任務數量,從而達到高效的系統運行。
4.3 并發隊列
上邊我們涉及到的阻塞隊列會有很多的消費者(線程)去操作隊列。我們舉個具體點的例子,還是拿排隊打飯的例子,如果一個窗口沒有排序秩序,100 多個人都往窗口買飯,如果你作為賣飯的,想象一下會出現什么情況呢?
學生爭來爭去到底先給哪一個盛飯呢?一旦人一多,可能整個餐廳窗口擠爆,會出現打架的情況。
話說回來,在系統中也可能出現這種情況的,那我們怎么對付這種情況呢?此時的隊列不再叫做阻塞隊列,叫做并發隊列。
我們只需要設置一個鎖機制,當有一個消費者來取任務的時候,我們此時加一個鎖,說明其他的消費者不能進行操作了,當這個消費者讀取完任務時,在解鎖,依次類推,這樣保證了系統的正常運行。
總結
最后我們來總結一下隊列的應用,像我們開篇所說,隊列一般應用在有限的資源場景中,比如消息隊列、異步隊列、CPU 的線程執行隊列等。對于這些應用場景,都是利用了隊列先來先去的服務調度方式,從而能夠準確的對資源進行把控。
隊列在實際應用中也分為兩種,一種是基于數組的順序隊列,另一種是基于鏈表的鏈式隊列。它們兩者各有優缺點,所謂的優缺點也是由數組和兩邊本身的優缺點演化而來。
數組大小固定,如果有過多的請求,就會導致長時間排隊等候,請求響應時間過長。而鏈式隊列雖然可以動態的添加任務,但是如果過于太長,在實際應用中也是不允許的。
對于如何在實際應用中設計一個合適的隊列,需要根于已有的資源容量以及需求,還有系統的響應時間要求進行設計。如果隊列太長,會導致等待請求過多,隊列太小,就無法充分利用系統的資源。
基礎知識
基礎數據結構:【動畫】如何輕松手寫鏈表?
三分鐘基礎知識:什么是棧?
三分鐘基礎知識:互斥那點事兒(上)
三分鐘基礎知識:互斥那點事兒(下)
三分鐘基礎知識:用動畫給面試官解釋 TCP 三次握手過程
三分鐘基礎知識:用動畫給女朋友講解 TCP 四次分手過程
總結
以上是生活随笔為你收集整理的队列判空_三分钟基础:什么是队列?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 乐迪智能陪伴机器人_【团品】AI未来人工
- 下一篇: js大屏导出图片_整理了30个实用可视化