1. 程式人生 > >嚴蔚敏版資料結構學習筆記(4):佇列

嚴蔚敏版資料結構學習筆記(4):佇列

和上次的棧相反,佇列是一種先進獻出的線性表(FIFO);它只允許在它的一端進行刪除操作,而在另一邊進行插入操作。在佇列裡面,允許插入的一端我們稱之為隊尾,允許刪除的一端稱為隊頭;
這裡寫圖片描述
佇列和棧的基本操作差不多,也有八個,不同的一點是刪除操作是在表的頭部進行而不是尾部;
ADT Queue{
InitQueue(&Q);
DestroyQueue(&Q);
ClearQueue(&Q);
QueueEmpty(Q);
QueueLength(Q);
GetHead(Q,&e);
EnQueue(&Q,e);
DeQueue(&Q,&e);
QueueTraverse(Q,visit());
}
佇列中有一種限定性的資料結構是雙端佇列(Deque),是限定插入和刪除在表的兩端進行的線性表,兩端分別是端點1和端點2,實際中我們還可以定義限制輸入和限制輸出的雙端連結串列(也就是其中一端可以進行刪除和插入操作,另一端只能進行刪除(插入)操作);

佇列也有兩種儲存結構:順序的佇列和鏈式的佇列;
上面說到的都是順序佇列,鏈佇列需要兩個分別指向隊頭和隊尾的指標(頭指標和尾指標)才能唯一確定。和線性表的鏈式結構一樣,我們將給鏈式佇列一個頭結點,並令頭指標指向頭結點。所以可以清楚:鏈式佇列的判空操作是頭指標和尾指標均指向頭結點。如圖所示:
這裡寫圖片描述
每當一個新的資料元素存到佇列裡面頭指標不動,尾指標指向該新元素,頭結點也指向該元素。
我們先來頂一個鏈式結構的結構體:

typedef struct QNode{
    QElemType data;
    struct QNode *next;
}QNode,*QueuePtr;
typedef
struct{ QueuePtr front;//隊頭指標 QueuePtr rear;//隊尾指標 }LinkQueue;

其中包括了隊頭指標和隊尾指標,和資料元素;
同樣的,鏈式佇列也是有上面的八種基礎操作的,我們來試著一一實現一下:
構造一個空的鏈佇列:

Status InitQueue(LinkQueue &Q){
    Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));
    if(!Q.front) exit(OVERFLOW);//當記憶體分配失敗的時候
    Q.front->next = NULL;//此時front指向的結點就是頭結點
return OK; }

當然有了建立一個佇列,自然還要有佇列的銷燬和清空:

Status DestroyQueue(LinkQueue &Q){
    //銷燬一個佇列Q
    while(Q.front){
        Q.rear = Q.front->next;
        free(Q.front);
        Q.front = Q.rear;//釋放一塊記憶體要做兩點:1.釋放指向它的指標。2.將該指標指向空
    }
    return OK;
}

至於為什麼要用迴圈呢,我之前也是迷茫了一下,第一次迴圈的時候front指向的是頭結點,然後將這個front->next==NULL賦值給rear之後front依然存在,在將這個賦值給rear之後我們就達成了front和rear都指向空,也就是實現了銷燬

Status ClearQueue(LinkQueue &Q){
    //清空一個佇列Q
    Q.rear = Q.front;
    struct QNode *p,*q;
    p = Q.front->next;
    Q.front->next = NULL;//只留下頭結點
    while(p){
        q=p;
        p = p->next;
        free(q);
    }
    return OK;
}

清空一個鏈式佇列的話只要留下頭結點 就行;達成頭指標和尾指標均指向頭結點即可;
(剩下的部分會在接下來的時間裡慢慢上載的。)