隊列----循環隊列

隊列:只允許在一段進行插入,在另一端進行刪除的線性表。

循環隊列:具有隊頭指針和隊尾指針,指示隊列元素所在的位置,避免刪除元素時移動大量元素。

循環隊列特性:

  • 只能隊尾插入元素、在隊頭刪除元素。
  • 先進先出(First In First Out)的線性表,先進入的元素出隊,後進入的元素才能出隊。

優點:

  • 相比普通的隊列,元素出隊時無需移動大量元素,只需移動頭指針。
  • 適合處理用戶排隊等待的情況。

缺點:

  • 需要預先分配大量存儲空間。

時間複雜度

  • 讀取時的時間複雜度爲O(1)。
  • 插入、刪除時的時間複雜度爲O(1)。

隊列示意圖

循環隊列插入元素示意圖

循環隊列刪除元素示意圖

// 隊列(循環隊列)
#include <stdio.h>

#define OK 1      // 執行成功
#define ERROR 0   // 執行失敗
#define TRUE 1    // 返回值爲真
#define FALSE 0   // 返回值爲假
#define MAXSIZE 20 // 存儲空間初始分配大小

typedef int Status; // 函數返回結果類型
typedef int ElemType; // 元素類型

// 循環隊列的順序存儲結構
typedef struct {
    ElemType data[MAXSIZE]; // 存儲隊列元素
    int front; // 頭指針
    int rear; // 尾指針
} SqQueue;

/**
 * 初始化隊列
 * @param Q 隊列
 * @return 執行狀態
 */
Status InitQueue(SqQueue *Q) {
    Q->front = Q->rear = 0;
    return OK;
}

/**
 * 清空隊列
 * @param Q 隊列
 * @return 執行狀態
 */
Status ClearQueue(SqQueue *Q) {
    Q->front = Q->rear = 0;
    return OK;
}

/**
 * 判斷隊列是否爲空
 * @param Q 隊列
 * @return 隊列是否爲空
 */
Status QueueEmpty(SqQueue Q) {
    // 頭指針等於尾指針,隊列爲空
    if (Q.front == Q.rear) {
        return TRUE;
    } else {
        return FALSE;
    }
}

/**
 * 獲取隊列長度
 * @param Q 隊列
 * @return 隊列長度
 */
int QueueLength(SqQueue Q) {
    return (Q.rear - Q.front + MAXSIZE) % MAXSIZE;
}

/**
 * 獲取隊列頭元素
 * @param Q 隊列
 * @param e 存儲頭元素值
 * @return 執行狀態
 */
Status GetHead(SqQueue Q, ElemType *e) {
    // 隊列爲空,獲取失敗
    if (Q.front == Q.rear) {
        return ERROR;
    }

    *e = Q.data[Q.front]; // 將隊列頭元素存儲到元素e中
    return OK;
}

/**
 * 在隊列的隊尾處插入元素
 * @param Q 隊列
 * @param e 插入元素值
 * @return 執行狀態
 */
Status EnQueue(SqQueue *Q, ElemType e) {
    // 隊列滿時,插入失敗
    if ((Q->rear + 1) % MAXSIZE == Q->front) {
        return ERROR;
    }

    Q->data[Q->rear] = e; // 在隊尾處插入元素e
    // 隊尾指針向後移動,若到最後則轉向數組頭部
    Q->rear = (Q->rear + 1) % MAXSIZE;
    return OK;
}

/**
 * 刪除隊頭元素
 * @param Q 隊列
 * @param e 存儲出隊元素的值
 * @return 執行狀態
 */
Status DeQueue(SqQueue *Q, ElemType *e) {
    // 隊滿時,出隊失敗
    if (Q->front == Q->rear) {
        return ERROR;
    }

    *e = Q->data[Q->front]; // 將隊列頭元素存儲到元素e中
    // 隊頭指針向後移動,若到最後則轉向數組頭部
    Q->front = (Q->front + 1) % MAXSIZE;
    return OK;
}

/**
 * 打印單個元素
 * @param e 元素值
 * @return 執行狀態
 */
Status visit(ElemType e) {
    printf("%d ", e);
    return OK;
}

/**
 * 遍歷隊列中的元素
 * @param Q 隊列
 * @return 執行狀態
 */
Status QueueTravel(SqQueue Q) {
    int i; // 用於遍歷元素的下標
    i = Q.front; // 指向隊頭指針

    printf("[ ");
    // 當指針不等於隊尾指針
    while (i != Q.rear) {
        visit(Q.data[i]); // 打印單個元素的值
        i = (i + 1) % MAXSIZE; // 獲取下個元素的下標
    }
    printf("]\n");
    return OK;
}

int main() {
    Status status; // 執行狀態
    int i = 0, j;
    ElemType e; // 元素值
    SqQueue Q; // 隊列

    /*** 初始化隊列 ***/
    InitQueue(&Q); // 初始化隊列
    printf("初始化隊列後,隊列是否爲空?%s\n", QueueEmpty(Q) == TRUE ? "是" : "否");

    /*** 向隊列中插入10個元素 ***/
    for (j = 1; j <=10; ++j) {
        EnQueue(&Q, j); // 將元素j插入隊列
    }
    printf("插入10個元素後隊列的值爲:");
    QueueTravel(Q); // 遍歷隊列
    printf("隊列的長度爲:%d\n", QueueLength(Q)); // 獲取隊列長度
    printf("插入10個元素後,隊列是否爲空?%s\n", QueueEmpty(Q) == TRUE ? "是" : "否");

    /*** 刪除隊列中的五個元素,並打印對應的值 ***/
    printf("開始刪除元素:\n");
    for (j = 0; j < 5; ++j) {
        DeQueue(&Q, &e); // 刪除隊頭元素,將值存到e中
        printf("元素%d出隊\n", e);
    }
    printf("5個元素出隊後,隊列中的值爲:");
    QueueTravel(Q); // 遍歷隊列
    printf("隊列的長度爲:%d\n", QueueLength(Q));  // 獲取隊列長度

    /*** 獲取隊列頭元素的值 ***/
    status = GetHead(Q, &e); // 獲取隊列頭元素
    if (status) {
        printf("隊列頭元素爲:%d\n", e);
    }

    /*** 清空隊列元素 ***/
    ClearQueue(&Q); // 清空隊列元素
    printf("清空隊列後,隊列是否爲空:%s\n", QueueEmpty(Q) == TRUE ? "是" : "否");
    printf("隊列中的元素爲:");
    QueueTravel(Q); // 遍歷元素
    return 0;
}

                                                                運行結果
作者:lkmc2
鏈接:https://www.jianshu.com/p/962e0f3dd607
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯繫作者獲得授權並註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章