數據結構與算法06——隊列之循環隊列

隊列

與棧不一樣,他就是現實中排隊同樣,講究先來後到,即 先進先出
打個比方,你告訴朋友咱們作地鐵去西湖,你輸入 "s-u-b", 若是按照棧 先入後出後入先出 的方式,朋友會收到 b-u-s, what?有地鐵,咱們幹嗎作兩個小時的汽車??? 隊列就可讓朋友按你輸入的順序依次收到 s-u-bbash

簡單的看一下隊列,是線性結構,想到什麼?很是熟悉的 線性表 ,有兩種存儲結構,順序存儲和鏈式存儲。 咱們今天先講一講隊列的順序存儲結構——循環隊列markdown

先看一種隊列

假設開闢一個存儲大小爲5個內存單元的隊列
我列舉了四種狀態 :空隊列,入隊,入隊到隊滿,刪除只剩一個元素。 先看前三種:當爲空隊列時,front和rear都指向了同一個元素,判爲空;當入隊時,rear向後移動,指向新元素,當出隊時,front指向下一個元素;當front=0,rear=4時,整隊滿,操做貌似沒有問題。這一切看似完美。

可是,,,若是以下圖,出隊到只剩最後一個元素,front和rear又都指向了一個同元素,並且僅在隊尾,又要認爲隊列爲空?不可能啊,明明最後一塊存儲單元還有一個元素,並且卻不能繼續入隊新元素,超出了存儲範圍,若是要繼續利用前面出隊的空餘空間,又該怎麼用?函數

若是 咱們把隊列設計成下面這樣:測試

哈哈,循環了。隊尾rear指向下一個位置,而不是當前的隊尾元素。

  • 如圖(b)所示,a先入隊 b再入隊 C再入隊 ,rear指向C後面的位置。
  • 如圖(c)所示,隊首元素a出隊,front指向下一個隊首b,可是此時front=1,而再也不是從0開始,一邊出隊一邊入隊,那麼front的位置就會是0,1,2,3,4,5 而後利用取模運算front = (front+1) % max,front又回到0,而後1。。。。。 使得每次front的位置能夠在隊尾以後繼續回到標號從0的位置繼續日後走,週期循環。同理,rear,新增到rear = 5時,也利用取模運算,新的數據從標號爲0開始繼續入隊,實現循環隊列。
  • 若是隊盡是什麼樣,看下圖

????? rear指向的下一個位置是隊首front的b,哇,仍是和以前同樣,front==rear, 可是咱們已經用循環解決當只有最後一塊存儲單元有元素而不能再繼續入隊的問題。
無礙,咱們能夠犧牲一個front前的存儲單元,用來保持隊尾和隊首的距離,來解決最後一個問題:判斷隊滿,(Q.rear+1) % Q.max == Q.front , 若是條件成立,意味着空的下一個位置就是隊首front,此時隊已滿

這就是循環隊列的工做流程spa

循環隊列

將上面的過程作一下整理:
設計

  1. 當初始化隊列爲空時,front = rear = 0;
  2. 入隊,rear+1,指向隊尾的下一個存儲單元,爲了實現循環利用取模運算:rear = (rear+1) % max;
  3. 出隊,front+1,指向下一個隊首,實現循環:front = (front+1) % max;
  4. 判斷隊滿,(Q.rear+1) % Q.max == Q.front

定義

#define ERROR 0
#define TRUE 1
#define FALSE 0
#define OK 1
#define MAXSIZE 20 /* 存儲空間初始分配量 */

typedef int Status;/* Status是函數的類型,其值是函數結果狀態代碼,如OK等 */
typedef int ElemType;/* ElemType類型根據實際狀況而定,這裏假設爲int */

/* 隊列結構 */
typedef struct
{
    ElemType *data;
    int front;  /* 記錄隊首元素位置 */
    int rear;   /* 記錄對尾元素位置 */
    int max;    /* 記錄開闢內存空間的大小 */
}SqQueue;
複製代碼

初始化建立隊列

/// 初始化建立隊列
/// @param Q 隊列指針
/// @param n 指定開闢空間大小,一個空間大小是 sizeof(ElemType)
Status InitQueue(SqQueue *Q, int n)
{
    Q->data = malloc(sizeof(ElemType) * n);
    if (Q->data == NULL) return ERROR;
    
    Q->max = n;
    Q->front = Q->rear = 0;
    
    return OK;
}

複製代碼

得到元素個數

/// 獲取隊列元素個數(包括rear指向的空位置)
/// @param Q 隊列
int GetLength(SqQueue Q)
{
    return (Q.rear - Q.front + Q.max) % Q.max;
}
複製代碼

判斷是否是空

Status QueueEmpty(SqQueue Q)
{
    if (Q.front == Q.rear) {
        return OK;
    }
    return ERROR;
}
複製代碼

隊滿

Status QueueFull(SqQueue Q)
{
    if ((Q.rear+1) % Q.max == Q.front)
    {
        return OK;
    }
    else
    {
        return ERROR;
    }
}
複製代碼

得到隊首元素

Status GetFront(SqQueue Q, ElemType *e)
{
    if (QueueEmpty(Q) == OK) {
        return ERROR;
    }
    
    *e = Q.data[Q.front];
    return OK;
}
複製代碼

入隊

/// 入隊操做
/// @param Q 隊列
/// @param e 新數據
Status EnQueue(SqQueue *Q, ElemType e)
{
    // 判斷隊列有沒有滿
    if (QueueFull(*Q)) return ERROR;
    
    Q->data[Q->rear] = e;
    // 隊尾向後移動,取模運算,超出隊尾,實現循環繼續從隊首開始
    Q->rear = (Q->rear+1) % Q->max;
    
    return OK;
}
複製代碼

出隊

/// 出隊列
/// @param Q 隊列
/// @param e 出的元素
Status DeQueue(SqQueue *Q, ElemType *e)
{
    // 判斷對了是否是空
    if (QueueEmpty(*Q) == OK) return ERROR;
    
    *e = Q->data[Q->front];
    // 隊首位置向後移動一位
    Q->front = (Q->front+1) % Q->max;
    
    return OK;
}
複製代碼

遍歷輸出

Status QueuePrint(SqQueue *Q)
{
    /* 從隊首開時輸出,直到對尾 */
    int i = Q->front;
    while (i != Q->rear) {
        printf("%d ",Q->data[i]);
        i = (i+1) % Q->max;
    }
    printf("\n");
    
    return ERROR;
}
複製代碼

測試輸出

指定隊列最大存儲5個單元,方便觀看指針

int main(int argc, const char * argv[]) {
    
    SqQueue queue;
    InitQueue(&queue, 5);
    
    printf("插入數據:");
    for (int i = 0; i < 30; i++) {
        EnQueue(&queue, i);
    }
    QueuePrint(&queue);
    
    int e ;
    
    printf("出隊:");
    if (DeQueue(&queue, &e))
    {
        QueuePrint(&queue);
    }
    if (DeQueue(&queue, &e))
    {
        QueuePrint(&queue);
    }
    
    
    int frontE;
    if (GetFront(queue, &frontE)) {
        printf("隊頭:%d\n",frontE);
    }
    
    printf("插入數據:");
    scanf("%d",&e);
    EnQueue(&queue, e);
    QueuePrint(&queue);
    
    printf("插入數據:");
    scanf("%d",&e);
    EnQueue(&queue, e);
    QueuePrint(&queue);
    
    printf("插入數據:");
    scanf("%d",&e);
    EnQueue(&queue, e);
    QueuePrint(&queue);
    
    printf("插入數據:");
    scanf("%d",&e);
    EnQueue(&queue, e);
    QueuePrint(&queue);
    
    printf("開始清空隊列\n");
    ClearQueue(&queue);
    QueuePrint(&queue);
    
    DestoryQueue(&queue);
    
    return 0;
}
複製代碼

相關文章
相關標籤/搜索