隊列的實現(1):循環隊列的實現

隊列是一種“先進先出的數據結構”,可分爲靜態隊列和鏈式隊列。靜態隊列一般使用數組實現,數組需要預先定義內存大小,爲了避免內存浪費,一般使用循環隊列。接下來講述循環隊列的原理以及實現代碼。

循環隊列數據結構定義:
int front;//指向隊列頭,指向第一個數據節點
int rear;//指向隊列尾(並不是指向最後一個數據節點,而是最後一個數據節點後面的位置)
char data[];//節點數據,根據實際需要可以是不同的數據類型,但是因爲是數組,需要在聲明時指定大小

循環隊列操作方法:

void circQue_Init(circQue_t* queue);`//初始化data數組的數據,front和rear設爲0
void circQue_Deinit(circQue_t* queue);//銷燬隊列
bool isQueEmpty(circQue_t* queue);//檢查隊列是否爲空,在獲取隊列最前面的數據前需要檢查隊列是否爲空,判斷依據是front是否和rear相等(不一定都是0)
bool isQueFull(circQue_t* queue);//檢查隊列是否已滿,在往隊列插入新的節點前需要檢查隊列是否已經滿,判斷依據是(rear+1)%dataLen == front,因爲rear永遠指向最後一個節點後面的位置,也就是說數組大小雖然是dataLen,但是實際最多隻能存儲dataLen-1個節點
bool circQue_add(circQue_t* queue, char newData);//往隊列插入節點(即隊列最後一個節點)
char circQue_remove(circQue_t* queue);//從隊列移除節點(即隊列第一個節點)
void printQueueData(circQue_t* queue);//打印隊列數據

通常會比較疑惑的是,爲什麼rear不指向最後一個數據節點,而是指向最後一個節點後面的位置?
考慮這個情況:爲什麼我們要用(rear+1)%dataLen == front作爲隊列滿的條件?因爲如果使用rear==front作爲判斷條件,那麼就和隊列空的判斷條件重複了,無法知道到底是滿還是空。因此需要預留一個空間,當rear的後一個位置是front,說明隊列已經滿了。

隊列滿的情況:

還有一個容易犯的錯誤,循環隊列的遍歷。簡單的數組或者單鏈表的遍歷,都是從首位置開始,然後每次++,但是循環隊列存在這樣的情況:rear比front小,這個時候如果從front開始,每次自增1直到等於rear,條件將永遠不成立。
舉個例子,一個最多可存儲5個元素的循環隊列

插入三個節點,此時:
front爲0,rear爲3
將兩個節點移除出隊列,此時:
front爲2,rear爲3
插入三個節點,此時:
front爲2,rear爲1

可以看到,這就是循環隊列的特點,rear的值已經比front小了

因此,採用下面的循環遍歷隊列:

for(int i = queue->front; i != queue->rear; i=(i+1)%MAX_NODE_NUM)

i = queue->front; while(i% MAX_NODE_NUM!= queue ->rear){…;i++}

以下是實現循環隊列的源碼:

#include <string.h>
#include <malloc.h>
#include <iostream>

#define MAX_NODE_NUM 10

using namespace std;

typedef struct circQueue{
    int front;
    int rear;
    char data[MAX_NODE_NUM];
}circQue_t; 

void circQue_Init(circQue_t* queue){        
    queue->front = 0;
    queue->rear = 0;
    memset(queue->data, 0, MAX_NODE_NUM);
}

void circQue_Deinit(circQue_t* queue){
    if(queue){
        cout << "will free queue,front is:" << queue->front <<",rear is:" << queue->rear << endl;
        free(queue);
    }
}

bool isQueEmpty(circQue_t* queue){
    return (queue->front == queue->rear);//when front equal rear means circular queque is empty
}

bool isQueFull(circQue_t* queue){
    return (((queue->rear + 1) % MAX_NODE_NUM == queue->front));//get the value of rear plus 1, then mod capacity of circular queue, queue is full if the result of mod is equal front  
}

bool circQue_add(circQue_t* queue, char newData){
    if(isQueFull(queue)){
        cout << "queue is full, add node failed!" << endl;  
        return false;   
    }
    queue->data[queue->rear] = newData;
    queue->rear = (queue->rear+1)%MAX_NODE_NUM;
    cout << "front is:" << queue->front << ",rear is:" << queue->rear << endl;
    return true;
}

char circQue_remove(circQue_t* queue){
    if(isQueEmpty(queue)){
        cout << "queue is empty, remove node failed!" << endl;  
        return 'x';         
    }
    char nodeValue = queue->data[queue->front];
    queue->front = (queue->front+1)%MAX_NODE_NUM;
    return  nodeValue;
}

void printQueueData(circQue_t* queue){
    for(int i = queue->front; i != queue->rear; i=(i+1)%MAX_NODE_NUM){
        cout << queue->data[i] << " ";
    }
    cout << endl;
}

int main(){
    circQue_t* que = (circQue_t*)malloc(sizeof(circQue_t));
    if(!que){
        cout << "malloc for circular queque failed!" << endl;
        return -1;  
    }   

    circQue_Init(que);

    circQue_add(que, 'a');
    circQue_add(que, 'b');
    circQue_add(que, 'c');
    printQueueData(que);
    circQue_remove( que);
    printQueueData(que);
}
發佈了46 篇原創文章 · 獲贊 22 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章