1. 程式人生 > >大話資料結構筆記_佇列

大話資料結構筆記_佇列

總結:
  • 定義 : 只允許在一端進行插入操作, 而在另一端進行刪除操作的線性表。 是一種FIFO的線性表。
  • 順序結構, 避免陣列移動 , 和頭指標前面空間的浪費, 使用迴圈佇列
  • 迴圈佇列判斷 空佇列 和 佇列滿的兩種方法
    • 1.增加falg標記
    • 2.在滿時候 rear 和 front 之間空一個元素。
      • 滿的時候 : (rear + 1 ) % MAXSIZE == front
      • 空的時候 : front == rear
      • 佇列的長度 : (rear - front + MAXSIZE) % MAXSIZE
  • 順序結構 和 鏈式結構的比較: 看最後;
定義: 佇列(Queue) : 只允許在一端進行插入操作, 而在另一端進行刪除操作的 線性表。 是一種FIFO的線性表。 ADT:
佇列的ADT:
ADT Queue Data: 同線性表。元素具有相同的型別, 相鄰的元素具有前驅 和 後繼關係 Operations: InitQueue(*Q) : 初始化操作, 建立一個空的佇列Q。
DestroyQueue(*Q) : 若佇列存在, 則銷燬它。 ClearQueue(*Q) : 將佇列清空。 QueueEmpty(Q) : 若佇列為空, 返回true, 否則返回false GetHead(Q, *e): 若佇列非空, 用e返回佇列Q的頭元素 EnQueue(*Q, e): 若佇列Q存在, 插入新的元素e到佇列Q中併成為隊尾巴元素。 DeQueue(*Q, *e): 刪除佇列Q中的隊頭元素, 並用e返回其值。
QueueLength(Q): 返回佇列Q的元素個數。 endADT
ADT->順序儲存->語言實現: 順序儲存的不足: 如果固定 下標為 0 的位置為 隊頭 , 則每次出佇列的時候, 後面元素都要向前移動(時間 複雜度為O(n) , ), 因此使用 隊頭指標 和 隊尾指標的方式 就能將出佇列的操作時間複雜度降 低為O(1) 但是如果只 是簡單的使用頭指標和尾巴指標會造成浪費空間滯留在順序記憶體的前端, 也 就是雖然元素出佇列, 但是頭指標前的空間依然不能用的情況, 此時將順序佇列改裝成 迴圈樣 式的順序佇列解決空間浪費的問題。 【 也就是假溢位的問題 】 迴圈佇列: 首位相接的順序的結構,叫做迴圈佇列。 但是當 佇列滿時候 和 佇列為空的時候 均為 front == rear , 因此 :
  • 使用一個標誌flag , 未滿時為0 , 滿時候為1
  • 在front 和 rear 之間留一個空位
    • 當(rear+1) % QueueSize == front 時候為滿, 否則為不滿
公式: 計算佇列中元素的公式 : (rear - front + QueueSize) % QueueSize
迴圈佇列結構體定義 和 介面宣告 檔名 : SqQueue.h
 

/*****************************************************************************

File name: SqQueue.h Description: 迴圈佇列的結構體的定義和操作介面宣告 Author: MusaGeek Version: 1.0 Date: 2018-11-26 *****************************************************************************/ #ifndef __SQQUEUE_H #define __SQQUEUE_H #define MAXSIZE 20 #define FALSE 0 #define TRUE 1 typedef int QElemType; typedef int BOOL; typedef unsigned int uint; /*迴圈佇列的結構體*/ typedef struct { QElemType data[MAXSIZE]; /*順序結構*/ int front; /*頭指標*/ int rear; /*尾巴指標*/ }SqQueue; /*部分介面宣告*/ extern BOOL InitQueue(SqQueue *Q); extern uint QueueLength(SqQueue Q); extern BOOL EnQueue(SqQueue *Q, QElemType e); extern BOOL DeQueue(SqQueue *Q, QElemType *e); #endif
迴圈佇列的操作實現: 檔名 : SqQueue.c
說明 : 內部只有部分關鍵操作的實現 , 其他操縱的實現省略
/****************************************************** File name: SqQueue.c Description: 迴圈佇列的操作的實現 Author: MusaGeek Version: 1.0 Date: 2018-11-26 Function List: ******************************************************/ #include <stdio.h> #include "SqQueue.h" /************************************************* Function: InitQueue Description: 初始化迴圈佇列的頭指標 和 尾指標 為0 Input: Q : 指向順序佇列的指標 Return: BOOL TRUE : 初始化成功 *************************************************/ BOOL InitQueue(SqQueue *Q) { Q->front = 0; Q->rear = 0; return TRUE; } /************************************************* Function: QueueLength Description: 獲取佇列的長度 公式 : (rear - front + MAXSIZE) % MAXSIZE; Input: Q : 迴圈佇列的拷貝 Return: 迴圈佇列的長度 uint -> unsigned int *************************************************/ uint QueueLength(SqQueue Q) { reuturn (Q.rear - Q.front + MAXSIZE) % MAXSIZE; } /************************************************* Function: EnQueue Description: 若佇列未滿則插入元素 1.判斷佇列未滿否 , 否 返回FALSE 2.在rear指標處放置元素 3.rear 指標向後移動 4.返回TRUE 判斷滿的公式: 若 (rear + 1) % MAXSIZE == front 滿 Input: Q : 指向迴圈佇列的指標 e : 插入的元素 Return: BOOL TRUE:插入成功 FALSE:插入失敗 *************************************************/ BOOL EnQueue(SqQueue *Q, QElemType e) { if((Q->rear + 1) % MAXSIZE == Q->front) /*判斷佇列滿否*/ return FALSE; Q->data[Q->rear] = e; Q->rear = (Q->rear + 1) % MAXSIZE; return TRUE; } /************************************************* Function: DeQueue Description: 頭指標指向的元素出佇列 1.判斷佇列為空否 : 空則返回FALSE 2.將front 指標指向的元素通過e傳出 3.front 指標向後移動 4.return TRUE Input: Q : 迴圈佇列的拷貝 Output: e : 傳出引數 , 頭指標指向的元素 Return: BOOL TRUE : 出佇列成功 FALSE : 出佇列失敗 *************************************************/ BOOL DeQueue(SqQueue *Q, QElemType *e) { if(Q->rear == Q->front) /*佇列為空*/ return FALSE; *e = Q->data[Q->front]; Q->front = (Q->front + 1) % MAXSIZE; /*頭指標向後移動*/ return TRUE; }
ADT->鏈式儲存->語言實現: 圖解:
鏈式佇列結構體定義 和 介面宣告 檔名 : LInkQueue.h
/***************************************************************************** File name: LinkQueue.h Description: 鏈式儲存佇列的結構體的定義和操作介面宣告 Author: MusaGeek Version: 1.0 Date: 2018-11-26 *****************************************************************************/ #ifndef __LINKQUQUE_H #define __LINKQUQUE_H #define TRUE 1 #define FALSE 0 typedef int QElemType; /*假設佇列儲存的型別是int*/ typedef int BOOL; typedef unsigned int uint; /*鏈式儲存中的結點結構*/ typedef struct QNode { QElemType data; struct QNode *next; }QNode, *QueuePtr; /*佇列的鏈式結構*/ typedef struct { QueuePtr front, rear; /*隊頭, 隊尾指標*/ }LinkQueue; /*部分介面說明*/ extern BOOL EnQueue(LinkQueue *Q, QElemType e); extern BOOL DeQueue(LinkQueue *Q, QElemType *e); extern BOOL InitQueue(LinkQueue *Q); #endif
鏈式佇列操作的實現 檔名 : LInkQueue.c
說明 : 內部只有部分關鍵操作的實現 , 其他操縱的實現省略
/****************************************************** File name: LinkQueue.c Description: 佇列鏈式儲存的操作的實現 Author: MusaGeek Version: 1.0 Date: 2018-11-26 Function List: ******************************************************/ #include <stdio.h> #include <stdlib.h> #include "LinkQueue.h" /************************************************* Function: InitQueue Description: 初始化鏈式佇列 建立連結串列的頭結點 , 將front 和 rear 均指向頭結點。 Input: Q: 指向鏈式佇列的指標 Return: BOOL TRUE : 初始化成功 FALSE : 初始化失敗 *************************************************/ BOOL InitQueue(LinkQueue *Q) { Q->front = (QueuePtr)malloc(sizeof(QNode)); if(!Q->front) return FALSE; Q->front->next = NULL; Q->rear = Q->front; } /************************************************* Function: EnQueue Description: 將元素插入佇列 1.建立一個新結點 , 將e 賦值給結點的data 2.將建立的結點增加的連結串列的尾部 3.尾指標指向建立的結點 4.返回TRUE Input: Q: 指向鏈式佇列的指標 Return: BOOL TRUE : 插入成功 FALSE : 插入失敗 *************************************************/ BOOL EnQueue(LinkQueue *Q, QElemType e) { QueuePtr node = (QueuePtr)malloc(sizeof(QNode)); if(!node) return FALSE; node->data = e; node->next = NULL; Q->rear->next = node; /*將node結點插入連結串列尾部*/ Q->rear = node; /*將尾指標指向node*/ return TRUE; } /************************************************* Function: DeQueue Description: 頭元素出佇列 1.判斷佇列是否為空 , 為空 返回 FALSE 2.將頭結點的 next 指向存放首元素的結點node的下一個結點 3.node結點的data通過e傳出 4.若rear為node , 說明刪除node以後佇列為空 , 應該將rear 指向 front 5.釋放node 6.返回TRUE Input: Q: 指向鏈式佇列的指標 Output: e : 通過e傳出首元素的值 Return: BOOL TRUE : 出佇列成功 FALSE : 出佇列失敗 *************************************************/ BOOL DeQueue(LinkQueue *Q, QElemType *e) { if(Q->front == Q->rear) /*判斷佇列是否為空*/ return FALSE; QueuePtr node = Q->front->next; Q->front->next = node->next; /*從佇列中刪除node結點*/ if(Q->rear == node) /*判斷是否佇列刪除node以後為空佇列*/ Q->rear = Q->front; /*若為空佇列,rear 指標 指向 front 指標指向的位置*/ *e = node->data; /*node結點的值傳出, 完成出佇列操作*/ free(node); return TRUE; }
比較: 時間 : 如果頻繁的插入 和 刪除, 鏈式佇列動態申請造成的時間開銷 有影響, 雖然插入 和 刪 除操作的時間複雜度均為1; 空間上 : 固定長度的迴圈佇列可能造成空間上的浪費, 鏈式佇列的會有兩個指標的額外開銷, 但是整體上的空間比較靈活。