环形队列设计
两道环形队列设计的题。
LeetCode 622. Design Circular Queue
LeetCode 641. Design Circular Deque
题目描述
一道题是环形 queue 的设计,circular queue is also called "Ring Buffer";另一道是环形 deque 的设计。给出了 API 要求给出实现。
解题思路
两道题实际上是一样的,开辟对应大小的缓冲区,然后环形的话使用取余操作来实现即可。
这里我们使用 head & tail 指向首尾元素,并额外多分配一个元素的空间作为哨兵,用于区分空队列和满队列。
参考代码
这里我们只给出 deque 的实现代码,因为 queue 实际上是限定了只能使用 deque 的部分功能,queue 的实现只需要截取 deque 对应部分的实现即可。
/*
* @lc app=leetcode id=641 lang=cpp
*
* [641] Design Circular Deque
*/
// @lc code=start
class MyCircularDeque {
int* data;
int cap;
int head, tail;
public:
/** Initialize your data structure here. Set the size of the deque to be k. */
MyCircularDeque(int k) :
data(new int[k+1]), cap(k+1), head(0), tail(k) {
}
~MyCircularDeque() {
delete[] data;
}
/** Adds an item at the front of Deque. Return true if the operation is successful. */
bool insertFront(int value) {
if (isFull()) {
return false;
}
head = (head - 1 + cap) % cap;
data[head] = value;
return true;
}
/** Adds an item at the rear of Deque. Return true if the operation is successful. */
bool insertLast(int value) {
if (isFull()) {
return false;
}
tail = (tail + 1) % cap;
data[tail] = value;
return true;
}
/** Deletes an item from the front of Deque. Return true if the operation is successful. */
bool deleteFront() {
if (isEmpty()) {
return false;
}
head = (head + 1) % cap;
return true;
}
/** Deletes an item from the rear of Deque. Return true if the operation is successful. */
bool deleteLast() {
if (isEmpty()) {
return false;
}
tail = (tail - 1 + cap) % cap;
return true;
}
/** Get the front item from the deque. */
int getFront() {
if (isEmpty()) {
return -1;
}
return data[head];
}
/** Get the last item from the deque. */
int getRear() {
if (isEmpty()) {
return -1;
}
return data[tail];
}
/** Checks whether the circular deque is empty or not. */
bool isEmpty() {
return head == (tail + 1) % cap;
}
/** Checks whether the circular deque is full or not. */
bool isFull() {
return head == (tail + 2) % cap;
}
}; // AC
/**
* Your MyCircularDeque object will be instantiated and called as such:
* MyCircularDeque* obj = new MyCircularDeque(k);
* bool param_1 = obj->insertFront(value);
* bool param_2 = obj->insertLast(value);
* bool param_3 = obj->deleteFront();
* bool param_4 = obj->deleteLast();
* int param_5 = obj->getFront();
* int param_6 = obj->getRear();
* bool param_7 = obj->isEmpty();
* bool param_8 = obj->isFull();
*/
// @lc code=end
拓展延伸
C++ 中的 queue 的实现是什么样的?
C++ 中的 queue 和 stack 一样,都并不是某一特定的类型,而是一个“适配器”。实际上,queue 的底层可以是一个双端队列 deque,也可以是一个双链表,默认是deque。
deque 对内存的管理是以页为单位分配数组,页内的元素在两端的操作都可以像普通数组一样操作;页与页之间并不是连续分配,而是使用链表或者索引表来管理,两端的 push/pop 操作可能触发页分配和页回收。通过这种策略,回收了空闲内存,也就是 “make use of the spaces in front of the queue”,当然 deque 也做到了 “make use of spaces in rear of the queue”。