問題描述:迴圈佇列是一般佇列的變種吧,就是將佇列首尾相連了,貌似這樣就不必考慮佇列滿而無法使用了,因為到了佇列尾又會迴圈回到佇列首。在嵌入式底層**實現中,一些串列埠資料特別是串列埠,用到迴圈佇列的情況還是蠻多的。當然,這只是一種資料結構,用在**都得看具體用途和是否能帶來好處。為了更深一步的對這一結構的了解,進行了下整理和學習。
迴圈佇列:將向量空間想象為乙個首尾相接的圓環,並稱這種向量為迴圈向量。儲存在其中的佇列稱為迴圈佇列(circular queue)。這個應當是比較成熟的定義了,簡潔了當。像是一條蛇咬住自己的尾巴,而且蛇腔裡面可以填充東西的感覺。
為什麼用迴圈佇列:主要是為了克服「假溢位」情況,
系統作為佇列用的儲存區還沒有滿,但佇列卻發生了溢位,我們把這種現象稱為"假溢位"。其實就是因為佇列的first in first out特質所引起的,隊列為獲得
first in first out特質,一般需要兩個指標,乙個稱為「頭指標」,乙個稱為「尾指標」,
頭指標用於在佇列頭部
讀出元素
,尾指標用於在佇列尾部
插入新元素
,先進去佇列的元素位於佇列的頭部。對於使用順序佇列情況,隨著佇列尾部不斷插入新元素,尾指標最終會指向分配給佇列的最後的記憶體位址,當再有新元素要插入時,此時佇列尾部已經無法插入新元素了。而頭指標由於有元素出佇列,佇列記憶體空間的前面一部分其實還是空的,因此就造成了「假溢位
」這種情況。迴圈佇列就是為解決該問題的。(當然,解決假溢位還可以將佇列元素做平移,但感覺使用迴圈佇列會有更高的效率)。
迴圈佇列弊端:迴圈佇列空和滿時都是頭指標等於尾指標,因此對於佇列空和滿的判斷需要在**中加以區別,有三種方式:一是另設一布林變數來區別佇列的空和滿。二是少用乙個元素的空間,每次入隊前測試入隊後頭尾指標是否會重合,如果會重合就認為佇列已滿。三是設定一計數器記錄佇列中元素總數,不僅可判別空或滿,還可以得到佇列中元素的個數。
迴圈佇列型別定義:
#define queuesize 100 //應根據具體情況定義該值
typedef char datatype; //datatype的型別依賴於具體的應用
typedef structcirqueue;
迴圈佇列的基本運算:
1. 佇列置空:
void initqueue(cirqueue *q)
2. 佇列判空:
int queueempty(cirqueue *q)
3. 判斷佇列是否滿:
int queuefull(cirqueue *q)
4. 元素佇列尾部入隊:
void enqueue(cirqueue *q,datatype x)
5. 元素從佇列頭部出佇列:
datatype dequeue(cirqueue *q)
迴圈佇列使用總結:優點是邏輯判斷簡單,執行程式實現容易。 缺點是執行時重複比較太多,效率不一定高,大型系統節點較多時不宜採用(重複比較太多的問題暫時未碰到,佇列用來傳遞fifo訊息的情況較多,重複比較問題以後碰到再補充)。
迴圈必須注意事項
今天在工作中遇見乙個場景 父元件向子元件中傳遞資料的時候,在子元件中父元件傳遞過來的資料進行迴圈的時候 子元件報錯 typeerror cannot read property menu pid of null at vuecomponent.gettree 後來發現報錯的原因是在進行迴圈的時候,g...
MQ 重試佇列注意事項
不要過度依賴訊息佇列的重試來保證最終消費成功 舉個例子,我們的消費訊息佇列的應用a依賴於應用b的某個介面,但是雙十一流量太大,應用b的介面qps不足,導致rpc超時返回 即本條訊息消費失敗 此條訊息會進入重試佇列。進入重試佇列不是萬能的 問題一 rocketmq重試16次還是不成功就會認為訊息消費不...
AudioRecord 使用小結與注意事項
使用專門的執行緒讀取資料,容易出現buffer overflow。使用 setrecordpositionupdatelistener時,要注意兩個問題 一 1.啟動錄音後,要先read buffer,才會通知啟用 listener。audiorecord startrecording audior...