數(shù)據(jù)結(jié)構(gòu)與算法(六)-- 隊(duì)列(Queue)

隊(duì)列具有新進(jìn)先出(FIFO)的特點(diǎn).

1 隊(duì)列的順序結(jié)構(gòu)

1.1 數(shù)據(jù)結(jié)構(gòu)

#define OK 1
#define ERROR 0

#define TRUE 1
#define FALSE 0

#define MAXSIZE 10

typedef int QElemType;
typedef int Status;

typedef struct {
    int data[MAXSIZE];  // 存放數(shù)據(jù)的數(shù)組
    int front;          // 隊(duì)首索引
    int rear;           // 隊(duì)尾索引
}SqQueue;

1.2 入棧和出棧的實(shí)現(xiàn)

假設(shè)一個(gè)可以容納5個(gè)元素的隊(duì)列,如下:

{ x, x, x, x, x }
  ^
 front
 rear

我們使用 x 表示這個(gè)位置還沒有插入任何元素.

此時(shí)隊(duì)列的frontrear 都為0。

我們將元素1 2 34 依次入隊(duì),那么現(xiàn)在隊(duì)列中的內(nèi)容如下:

{ 1, 2, 3, 4, x }
  ^           ^
front        rear

現(xiàn)在front0, rear4, 接下來我們將 12 出隊(duì),隊(duì)列內(nèi)容為:

{ x, x, 3, 4, x }
        ^     ^
      front  rear

接著,我們將元素5 6依次入隊(duì),當(dāng)元素6入隊(duì)時(shí),就會(huì)出現(xiàn)溢出,實(shí)際上隊(duì)列中還有3個(gè)空位,但是現(xiàn)在只能入隊(duì)1個(gè)元素,這里的溢出我們稱之為假溢出。

為了解決假溢出,將隊(duì)列的空間進(jìn)行充分的利用,這里我們可以引入了一個(gè)循環(huán)隊(duì)列的概念,當(dāng)隊(duì)尾索引等于數(shù)組的最大索引時(shí),當(dāng)下一個(gè)元素入隊(duì)時(shí),我們從數(shù)組的索引為0的位置開始入隊(duì)。那么現(xiàn)在將元素5 6入隊(duì)后,隊(duì)列的內(nèi)容如下:

{ 6, x, 3, 4, 5 }
     ^  ^     
   rear front  

這樣就能將充分的將空間利用起來, 但是現(xiàn)在又存在一個(gè)問題,如果我們繼續(xù)入隊(duì)元素7后:

{ 6, 7, 3, 4, 5 }
        ^
      front
       rear

這里隊(duì)首索引和隊(duì)尾索引又相等了,這時(shí)我們將無法區(qū)分隊(duì)列為空和隊(duì)列滿的時(shí)候。因此當(dāng)隊(duì)列中只有一個(gè)空位時(shí),我們就認(rèn)為隊(duì)列滿了,不能繼續(xù)入隊(duì),這樣隊(duì)列滿的時(shí)候他們首尾索引就不相等了。

{ 6, x, 3, 4, 5 }
     ^  ^     
   rear front  

1.3 代碼實(shí)現(xiàn)

// 1.初始隊(duì)列
Status initQueue(SqQueue *Q) {
    Q->front = 0;
    Q->rear = 0;
    return OK;
}

// 2.隊(duì)列清空
Status clearQueue(SqQueue *Q) {
    Q->front = 0;
    Q->rear = 0;
    return OK;
}

// 3.隊(duì)列是否為空
Status queueEmpey(SqQueue Q) {
    return Q.rear == Q.front;
}

// 4.隊(duì)列的長度
int queueLength(SqQueue Q) {
    return (Q.rear - Q.front + MAXSIZE) % MAXSIZE;
}

// 5.獲取隊(duì)列的頭部
Status getQueueHead(SqQueue Q, QElemType *e) {
    if (Q.rear == Q.front) return ERROR;
    *e = Q.data[Q.front];
    return OK;
}

// 6.入隊(duì)
Status enqueue(SqQueue *Q, QElemType e) {
    if ((Q->rear + 1) % MAXSIZE == Q->front) return ERROR;
    Q->data[Q->rear] = e;
    Q->rear = (Q->rear + 1) % MAXSIZE;
    return OK;
}

// 7.出隊(duì)
Status dequeue(SqQueue *Q, QElemType *e) {
    if (Q->front == Q->rear) return ERROR;
    *e = Q->data[Q->front];
    Q->front = (Q->front + 1) % MAXSIZE;
    return OK;
}

// 遍歷
void queueTraverse(SqQueue Q) {
    
    int i = Q.front;
    while (i != Q.rear) {
        printf("%d  ", Q.data[i]);
        i = (i + 1) % MAXSIZE;
    }
    printf("\n");
}

int main(int argc, const char * argv[]) {
    // insert code here...
    
    SqQueue Q;
    QElemType e;
    
    if (initQueue(&Q)) {
        printf("初始化隊(duì)列成功\n");
    }
    
    for (int i = 0; i < 10; i++) {
        enqueue(&Q, i);
    }
    printf("隊(duì)列中的元素為:");
    queueTraverse(Q);
    printf("隊(duì)列的長度為:%d\n", queueLength(Q));
    dequeue(&Q, &e);
    printf("獲取出隊(duì)元素:%d\n", e);
    printf("隊(duì)列中的元素為:");
    queueTraverse(Q);
    getQueueHead(Q, &e);
    printf("獲取隊(duì)列頭部:%d\n", e);
    printf("隊(duì)列是否為空:%d\n", queueEmpey(Q));
    printf("清空隊(duì)列\(zhòng)n");
    clearQueue(&Q);
    printf("隊(duì)列是否為空:%d\n", queueEmpey(Q));
    printf("隊(duì)列中的元素為:");
    queueTraverse(Q);
    printf("隊(duì)列的長度為:%d\n", queueLength(Q));
    
    return 0;
}

//輸出:
//初始化隊(duì)列成功
//隊(duì)列中的元素為:0  1  2  3  4  5  6  7  8
//隊(duì)列的長度為:9
//獲取出隊(duì)元素:0
//隊(duì)列中的元素為:1  2  3  4  5  6  7  8
//獲取隊(duì)列頭部:1
//隊(duì)列是否為空:0
//清空隊(duì)列
//隊(duì)列是否為空:1
//隊(duì)列中的元素為:
//隊(duì)列的長度為:0

2 隊(duì)列的鏈?zhǔn)浇Y(jié)構(gòu)

使用順序儲(chǔ)存結(jié)構(gòu)時(shí),會(huì)出現(xiàn)假溢出問題,因此我們引入循環(huán)隊(duì)列的概念來解決假溢出問題,這樣的話如果隊(duì)列滿了,要將隊(duì)列進(jìn)行擴(kuò)容時(shí),將會(huì)變得十分復(fù)雜。如果我們使用鏈?zhǔn)浇Y(jié)構(gòu)來實(shí)現(xiàn)隊(duì)列的話就沒有上面的問題。

2.1 數(shù)據(jù)結(jié)構(gòu)

#define OK 1
#define ERROR 0

#define TRUE 1
#define FALSE 0

typedef int QElemType;
typedef int Status;

typedef struct QNode {
    QElemType data;
    struct QNode *next;
}QNode, *QNodePtr;

typedef struct {
    QNodePtr front;
    QNodePtr rear;
    int count;
} LinkQueue;

2.2 代碼實(shí)現(xiàn)

// 1.初始化
Status initQueue(LinkQueue *Q) {
    if (Q == NULL) return ERROR;
    // 初始化頭結(jié)點(diǎn)
    Q->rear = Q->front = (QNodePtr)malloc(sizeof(QNode));
    if (Q->front == NULL) return ERROR;
    Q->front->next = NULL;
    Q->count = 0;
    return OK;
}

// 2.銷毀隊(duì)列
Status destoryQueue(LinkQueue *Q) {
    if (!Q) return ERROR;
    // 從頭結(jié)點(diǎn)開始依次釋放結(jié)點(diǎn)
    while (Q->front) {
        Q->rear = Q->front->next;
        Q->front = Q->front->next;
        free(Q->rear);
    }
    Q->count = 0;
    return OK;
}

// 3.清空隊(duì)列
Status clearQueue(LinkQueue *Q) {
    if (!Q) return ERROR;
    // 保留頭結(jié)點(diǎn),釋放其余結(jié)點(diǎn)
    QNodePtr p, q;
    // 指向首元結(jié)點(diǎn)
    p = Q->front->next;
    while (p) {
        q = p;
        p = p->next;
        free(q);
    }
    Q->front->next = NULL;
    Q->rear = Q->front;
    Q->count = 0;
    return OK;
}

// 4.隊(duì)列是否為空
Status queueEmpty(LinkQueue Q) {
    return Q.front == Q.rear;
}

// 5.獲取隊(duì)列的長度
int queueLength(LinkQueue Q) {
    return Q.count;
}

// 6.獲取隊(duì)頭
Status getQueueHead(LinkQueue Q, QElemType *e) {
    *e = Q.front->next->data;
    return OK;
}

// 7.入隊(duì)
Status enqueue(LinkQueue *Q, QElemType e) {
    if (!Q) return ERROR;
    QNodePtr p = (QNodePtr)malloc(sizeof(QNode));
    if (!p) return ERROR;
    p->next = NULL;
    p->data = e;
    Q->rear->next = p;
    Q->rear = p;
    Q->count++;
    return OK;
}

// 8.出隊(duì)
Status dequeue(LinkQueue *Q, QElemType *e) {
    if (!Q) return ERROR;
    if (Q->count == 0) return ERROR;
    // 獲取隊(duì)頭結(jié)點(diǎn)的值
    *e = Q->front->next->data;
    // 獲取隊(duì)頭結(jié)點(diǎn)
    QNodePtr p = Q->front->next;
    Q->front->next = p->next;
    free(p);
    Q->count--;
    // 刪空后,將隊(duì)尾指向頭結(jié)點(diǎn)
    if (Q->count == 0) Q->rear = Q->front;
    return OK;
}

// 9.遍歷
void queueTraverse(LinkQueue Q) {
    
    QNodePtr p = Q.front->next;
    
    while (p) {
        printf("%d  ", p->data);
        p = p->next;
    }
    printf("\n");
}

int main(int argc, const char * argv[]) {
    // insert code here...
    LinkQueue q;
    int e;
    
    if (initQueue(&q)) {
        printf("隊(duì)列初始化成功\n");
    }
    for (int i = 0; i < 10; i++) {
        enqueue(&q, i);
    }
    printf("隊(duì)列中的元素為:");
    queueTraverse(q);
    printf("隊(duì)列的長度為: %d\n", queueLength(q));
    printf("隊(duì)列是否為空: %d\n", queueEmpty(q));
    dequeue(&q, &e);
    printf("出隊(duì)元素為: %d\n", e);
    getQueueHead(q, &e);
    printf("獲取隊(duì)頭: %d\n", e);
    printf("隊(duì)列中的元素為:");
    queueTraverse(q);
    printf("隊(duì)列的長度為: %d\n", queueLength(q));
    printf("隊(duì)列是否為空: %d\n", queueEmpty(q));
    clearQueue(&q);
    printf("隊(duì)列中的元素為:");
    queueTraverse(q);
    printf("隊(duì)列的長度為: %d\n", queueLength(q));
    printf("隊(duì)列是否為空: %d\n", queueEmpty(q));
    destoryQueue(&q);
    
    return 0;
}

輸出:
隊(duì)列初始化成功
隊(duì)列中的元素為:0  1  2  3  4  5  6  7  8  9  
隊(duì)列的長度為: 10
隊(duì)列是否為空: 0
出隊(duì)元素為: 0
獲取隊(duì)頭: 1
隊(duì)列中的元素為:1  2  3  4  5  6  7  8  9  
隊(duì)列的長度為: 9
隊(duì)列是否為空: 0
隊(duì)列中的元素為:
隊(duì)列的長度為: 0
隊(duì)列是否為空: 1

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容