雙端隊列思想解析

我們先來看看定義是什麼。

deque (全名double-ended queue)即雙端隊列,是一種具有隊列和棧的性質的數據結構。雙端隊列中的元素可以從兩端彈出,其限定插入和刪除操作在表的兩端進行。

能夠看得懂嗎?反正最開始我是不能,但這確實是用很精煉的語言描述了雙端隊列的性質。這句話的內容蘊含這樣的信息deque在具備隊列的性質同時,deque的rear和front指針還具備棧的性質。這確實不太好理解,因爲這至少要求讀者熟悉棧和隊列的性質,並且需要付出一定時間成本來思考聯繫起來。等你掌握deque後再來看這句話,你會驚歎“這確實非常準確的描述了deque的性質,而且十分精煉”。

對此此時閱讀本文的你,我想應該是掌握了隊列纔會了學習雙端隊列,不然不太可能接觸到,並且還會來學習,畢竟正常人都會想學隊列。
即使你掌握了隊列,在此之前我還是會先稍微介紹下隊列,爲了使你完全清晰的理解我要說的內容。

隊列(queue)是隻允許在一端進行插入操作,而另一端進行刪除操作的線性表。
front:管理隊頭,負責出隊操作。
rear:管理隊尾,負責入隊操作。

上面是隊列中front和rear的 職責。下面我用可能是世界上最簡單語言來描述雙端隊列到底是什麼,性質如何。

雙端隊列就是隊列的puls版!和隊列的唯一區別就是,front和rear的職責不同,雙端隊列中front和rear的職責共享了!。

下面我來稍微解釋下(也行看到上面那句話你已經明白了):
rear即是隊列中的front也可作爲隊列中的rear,front亦是如此。那麼雙端隊列與隊列的唯一區別僅僅是rear和front的職責不同,那麼雙端隊列隊空和堆滿完全符號隊列中的判斷!
看到這裏,相信你已經理解什麼是雙端隊列了。爲了加深你的理解建議拿起紙筆,畫畫,然後趕緊去實現下。

最後,爲什麼我會學習雙端隊列呢?這其實是因爲我在LeetCode上刷題隊列的題目的時候,有一個題目要求設計一個雙端循環隊列,並實現對應操作,由此我纔去瞭解和學習雙端隊列。下面我以LeetCode的題目爲基礎,給出實現的代碼(C語言描述)。

設計實現雙端隊列。 你的實現需要支持以下操作:

MyCircularDeque(k):構造函數,雙端隊列的大小爲k。 insertFront():將一個元素添加到雙端隊列頭部。
如果操作成功返回 true。 insertLast():將一個元素添加到雙端隊列尾部。如果操作成功返回 true。
deleteFront():從雙端隊列頭部刪除一個元素。 如果操作成功返回 true。
deleteLast():從雙端隊列尾部刪除一個元素。如果操作成功返回 true。
getFront():從雙端隊列頭部獲得一個元素。如果雙端隊列爲空,返回 -1。 getRear():獲得雙端隊列的最後一個元素。
如果雙端隊列爲空,返回 -1。 isEmpty():檢查雙端隊列是否爲空。 isFull():檢查雙端隊列是否滿了。 示例:

MyCircularDeque circularDeque = new MycircularDeque(3); // 設置容量大小爲3
circularDeque.insertLast(1); // 返回 true
circularDeque.insertLast(2); // 返回 true
circularDeque.insertFront(3); // 返回 true
circularDeque.insertFront(4); // 已經滿了,返回 false
circularDeque.getRear(); // 返回 2 circularDeque.isFull();
// 返回 true circularDeque.deleteLast(); // 返回 true
circularDeque.insertFront(4); // 返回 true
circularDeque.getFront(); // 返回 4

提示:

所有值的範圍爲 [1, 1000] 操作次數的範圍爲 [1, 1000] 請不要使用內置的雙端隊列庫。

來源:力扣(LeetCode) 難度:中等
鏈接:https://leetcode-cn.com/problems/design-circular-deque

typedef struct MyCircularDeque 
{
    int front;
    int rear;
    int MAXSIZE;
    int data[];     //這是伸縮型數組成員,可以理解爲動態數組,大小依據內存分配而定。不明白自行查閱
} MyCircularDeque;


bool myCircularDequeIsEmpty(MyCircularDeque* obj);
bool myCircularDequeIsFull(MyCircularDeque* obj);


/** Initialize your data structure here. Set the size of the deque to be k. */
MyCircularDeque* myCircularDequeCreate(int k) {
    MyCircularDeque* obj = (MyCircularDeque*)malloc(sizeof(MyCircularDeque) + (k + 1) * sizeof(int));
    if(!obj)
        return NULL;
    memset(obj, 0, sizeof(MyCircularDeque) + (k + 1) * sizeof(int));
    obj->MAXSIZE = k + 1;

    return obj;
}

/** Adds an item at the front of Deque. Return true if the operation is successful. */
bool myCircularDequeInsertFront(MyCircularDeque* obj, int value) {
    if(myCircularDequeIsFull(obj))
        return false;

    obj->front = (obj->front - 1 + obj->MAXSIZE) % obj->MAXSIZE;
    obj->data[obj->front] = value;
    return true;
}

/** Adds an item at the rear of Deque. Return true if the operation is successful. */
bool myCircularDequeInsertLast(MyCircularDeque* obj, int value) {
    if(myCircularDequeIsFull(obj))
        return false;

    obj->data[obj->rear] = value;
    obj->rear = (obj->rear + 1) % obj->MAXSIZE;
    return true;
}

/** Deletes an item from the front of Deque. Return true if the operation is successful. */
bool myCircularDequeDeleteFront(MyCircularDeque* obj) {
    if(myCircularDequeIsEmpty(obj))
        return false;
    
    obj->front = (obj->front + 1) % obj->MAXSIZE;
    return true;
}

/** Deletes an item from the rear of Deque. Return true if the operation is successful. */
bool myCircularDequeDeleteLast(MyCircularDeque* obj) {  //OVER
    if(myCircularDequeIsEmpty(obj))
        return false;

     obj->rear = (obj->rear - 1 + obj->MAXSIZE) % obj->MAXSIZE;
     return true;
}

/** Get the front item from the deque. */
int myCircularDequeGetFront(MyCircularDeque* obj) { //OVER
    return myCircularDequeIsEmpty(obj) ? -1 : obj->data[obj->front];
}

/** Get the last item from the deque. */
int myCircularDequeGetRear(MyCircularDeque* obj) {  //OVER
    if(myCircularDequeIsEmpty(obj))
        return -1;

    int index = (obj->rear - 1 +obj->MAXSIZE) % obj->MAXSIZE;
    return obj->data[index];
}

/** Checks whether the circular deque is empty or not. */
bool myCircularDequeIsEmpty(MyCircularDeque* obj) { //OVER
    return obj->rear == obj->front ? true : false;
}

/** Checks whether the circular deque is full or not. */
bool myCircularDequeIsFull(MyCircularDeque* obj) {  //OVER
    return (obj->rear +1) % obj->MAXSIZE == obj->front ? true : false;
}

void myCircularDequeFree(MyCircularDeque* obj) {    //OVER
    free(obj);
    obj = NULL;
}

聲明:上面的代碼已經通過了LeetCode OJ系統的檢測,安心使用。

點個贊再走(* ^▽ ^*)吧

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