數據結構(10)隊列之順序隊列

前言

在隊列的順序存儲結構中,除了用一組地址連續的存儲單元來存放元素之外,一般還會附設兩個指針fount和rear來指示隊頭和隊尾元素的位置,這樣更有隊列的特點,但是它本質上仍是順序表。

順序隊列的初始化與插入刪除

通常約定,初始化空隊列時,讓fount和rear初始化爲0,每當需要插入元素(即新元素入隊)時,尾指針(rear)加一;要刪除元素(即隊首出隊)時,頭指針(fount)加一。這樣,在非空順序隊列裏,頭指針始終指向隊頭元素,尾指針則指向隊尾元素的下一個位置。

img_0

img_1

img_2

遍歷時,從fount指示的隊首位置開始,到rear指示的前一個位置結束。

順序隊列所存在的問題

在順序隊列中,當我們要執行插入操作時,首先需要判斷隊列是否已滿,如果隊列已滿是無法插入元素的;而判斷是否已滿的條件是看rear指針是否大於等於隊列最大容量。當然,在以往的順序表中,也可以重新去申請內存來實現插入的需求。但是先看看到我們的刪除操作,只是將fount指針自增,不進行其他操作。這樣就會造成一個現象:隊列邏輯上已經滿了(rear的指向已經越界了),實際上仍是有空間的(隊首元素之前的空間還可用)。

img_3

我們稱這種現象爲“假溢出”。顯然,在假溢出的情況下去重新申請內存是不合適的,合理的考慮是先充分利用之前的空間,這樣就出現了一種比較特殊的結構——循環隊列,會在下篇博客中詳細說明。
也有人會覺得:假如讓fount指針固定爲0,要出隊時將隊首元素後的所有元素向前移不就行了嗎?這樣的確可以解決假溢出的問題,但是每次出隊都要移動大量元素,性能就降低了。這也是順序隊列大多都設置爲循環隊列的原因——既解決問題,又保證了性能。

全部代碼

SeqQueue.h

#ifndef SeqQueue_h
#define SeqQueue_h

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#define ElemType int
#define MAXSIZE 8

typedef struct Queue{
    ElemType *base;
    int fount;
    int rear;
}Queue;

//初始化
void InitQueue(Queue *Q);

//入隊
void EnQueue(Queue *Q,ElemType x);
//出隊
void DeQueue(Queue *Q);
//展示
void ShowQueue(Queue *Q);

//獲取隊首元素
void GetHead(Queue *Q,ElemType *x);
//求長度
int GetLength(Queue *Q);
//清除
void CleatQueue(Queue *Q);
//摧毀
void DestoryQueue(Queue *Q);

#endif /* SeqQueue_h */

SeqQueue.c

#include "SeqQueue.h"

//初始化
void InitQueue(Queue *Q){
    //開闢空間
    Q->base = (ElemType *)malloc(sizeof(ElemType)*MAXSIZE);
    assert(Q->base != NULL);
    //隊頭指針和隊尾指針指向0下標
    Q->fount = Q->rear = 0;
}

//入隊
void EnQueue(Queue *Q,ElemType x){
    //判斷隊列是否滿
    if (Q->rear >= MAXSIZE) {
        //滿了
        printf("隊列已滿\n");
        return;
    }
    
    Q->base[Q->rear++] = x;
}
//出隊
void DeQueue(Queue *Q){
    //判斷隊列是否空
    if (Q->fount == Q->rear) {
        printf("隊列已空\n");
        return;
    }
    Q->fount++;
}

//展示
void ShowQueue(Queue *Q){
    for (int i = Q->fount; i < Q->rear; i ++) {
        printf("%4d",Q->base[i]);
    }
    printf("\n");
}

//獲取隊首元素
void GetHead(Queue *Q,ElemType *x){
    //判斷隊列是否空
    if (Q->fount == Q->rear) {
        printf("隊列已空\n");
        return;
    }
    *x = Q->base[Q->fount];
}
//求長度
int GetLength(Queue *Q){
    return (Q->rear - Q->fount);
}
//清除
void CleatQueue(Queue *Q){
    Q->fount = Q->rear = 0;
}
//摧毀
void DestoryQueue(Queue *Q){
    free(Q);
    Q->base = NULL;
}

Main.c

#include "SeqQueue.h"

int main(int argc, const char * argv[]) {
    Queue Q;
    InitQueue(&Q);
    
    //入隊
    for (int i = 0; i < 5; i ++) {
        EnQueue(&Q, i);
    }
    
    ShowQueue(&Q);
    
    //出隊
    DeQueue(&Q);
    
    ShowQueue(&Q);
    
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章