演算法與資料結構 二 佇列

2022-06-24 19:03:11 字數 2857 閱讀 5642

佇列也是一種線性的資料結構,它與鍊錶的區別在於鍊錶可以在任意位置進行插入刪除操作,而佇列只能在一端進行插入,另一端進行刪除。它對應於現實世界中的排隊模型。佇列有兩種常見的實現方式:基於列表的實現和基於陣列的實現

基於鍊錶的佇列,我們需要儲存兩個指標,乙個指向頭節點,乙個指向尾節點。

這種佇列不存在佇列滿的情況,當然也可以根據業務需求給定乙個最大值。當頭結點為空時表示隊列為空。由於佇列只能在隊尾插入資料,隊首刪除資料,因此針對佇列的插入需要採用鍊錶的尾插法,佇列元素的出隊需要改變頭指標。

佇列節點的定義與鍊錶節點的定義相同,下面給出各種操作的簡單實現

typedef struct _qnode

qnode, *lpqnode;

extern qnode* g_front;

extern qnode* g_real;

初始化操作,我們簡單的對兩個指標進行賦值

bool initqueue()

元素入隊的操作就是從佇列尾部插入,當隊列為空時,同時也是在隊首插入元素,因此針對元素入隊的操作,需要首先判斷佇列是否為空,為空時,需要針對隊首和隊尾指標進行賦值,而針對佇列不為空的情況下,只需要改變隊尾指標

bool enqueue(int nval)

memset(p, 0x00, sizeof(qnode));

p->nvalue = nval;

if (isqueueempty()) //判斷佇列是否為空

else

return true;

}

之前提到過,判斷佇列是否為空,只需要判斷兩個指標是否為空即可,因此這部分的**如下:

bool isqueueempty()

元素出隊需要從隊首出隊,同樣的需要判斷佇列是否為空。

bool dequeue(int *pval)

if (isqueueempty())

qnode *p = g_front;

//出隊之後需要判斷佇列是否為空,以便針對隊首、隊尾指標進行賦值

if (null == g_front->pnext)

else

free(p);

return true;

}

線性結構的佇列也可以使用陣列來實現,基於陣列的實現也需要兩個指標,分別是指向頭部的下標和指向尾部的下標

基於陣列的實現中有這樣乙個問題,那就是記憶體資源的浪費問題。假設現在有乙個能儲存10個元素的佇列,當前隊列為空,隨著元素的入隊,此時隊尾指標會一直向後偏移。當裡面有部分元素的時候,來進行元素出隊,這個時候隊首指標會向後偏移。那麼這個時候已經出隊的位置在佇列中再也訪問不到了,但是它所佔的記憶體仍然在那,這樣就造成了記憶體空間的浪費,隨著佇列的不斷使用,佇列所能容納的元素總數會不斷減少。如圖所示

基於這種問題,我們採用迴圈陣列的形式來表示乙個佇列,迴圈陣列的結構大致如下圖所示:

這種佇列的頭指標不一定小於尾指標,當隊首元素元素位於陣列的尾部,這個時候只要陣列中仍然有空閒位置來儲存資料的時候,可以將隊首指標再次指向陣列的頭部,從而實現空間的重複利用.

在這種情況下佇列的頭部指標的計算公式為: head = (head + 1) % maxsize,尾部的計算公式為 tail = (tail + 1) % maxsize

當隊列為空時應該是 head == tail,注意,由於陣列是迴圈陣列,此時並不一定能保證它們二者都為0,只有當佇列中從來沒有過資料,也就是說是剛剛初始化完成的時候它們才都為0

那麼隊列為滿的情況又怎麼確定呢?在使用普通陣列的時候,當二者相等都為maxsize的時候隊列為滿,但是在迴圈佇列中,並不能根據二者都等於maxsize來判斷佇列是否已滿,有可能之前進行過出隊的操作,所以在佇列頭之前的位置仍然能存資料,所以不能根據這個條件判斷。那麼是不是可以根據二者相等來判斷呢?答案是不能,二者相等是用來判斷隊列為空的,那麼怎麼判斷呢?這時候需要空出一塊位置作為隊尾的結束標誌,回想一下給出的迴圈陣列的例項圖,每當head與tail只間隔乙個元素的時候作為佇列已滿的標識。這個時候判斷的公式為 (tail + 1) % maxsize == head

下面給出各種操作對應的**

int g_queue[max_size] = ;

int g_front = 0;

int g_real = 0;

bool initqueue()

bool enqueue(int nval)

g_queue[g_real] = nval;

g_real = (g_real + 1) % max_size;

return true;

}

bool dequeue(int *pval)

if (isqueuefull())

*pval = g_queue[g_front];

g_front = (g_front + 1) % max_size;

return true;

bool isqueueempty()

bool isqueuefull()

最後從實現上來看基於陣列的佇列要比基於鍊錶的簡單許多,不需要考慮空指標,記憶體分配的問題,但是基於陣列的佇列需要額外考慮是否已滿的情況,當然這個問題可以使用動態陣列來避免。

JAVA資料結構與演算法(二)佇列

佇列是一種比較特殊的線性結構。它只允許在表的前端 front 進行刪除操作,而在表的後端 rear 進行插入操作。進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭。佇列中最先插入的元素也將最先被刪除,對應的最後插入的元素將最後被刪除。因此佇列又稱為 先進先出 fifo first in first...

資料結構(二) 佇列

一 佇列定義 佇列是限定在一端進行插入,另一端進行刪除特殊線性表。二 佇列基本操作 入隊出隊 三 佇列例題 1.例1 舞伴配對問題 分析 這一題是一道經典的取模運算,每一次將編號往前加一位,到達n就取模。include include include include int main return ...

資料結構 二 (佇列)

在模擬實現 佇列前應先簡單的了解先佇列的一些特點 佇列是一種特殊的線性表,特殊之處在於它只允許在表的前端 front 進行刪除操作,而在表的後端 rear 進行插入操作,和棧一樣,佇列是一種操作受限制的線性表。進行插入操作的端稱為隊尾,進行刪除操作的端稱為隊頭。佇列中沒有元素時,稱為空佇列。佇列最大...