Implementation
may use dynamic array and an index pointing to the head of the queue.
should support enqueue (appends a new element), dequeue (removes the first element).
class MyQueue {
private:
vector<int> data;
int p_start;
public:
MyQueue() {p_start = 0;}
bool enQueue(int x) {
data.push_back(x);
return true;
}
bool deQueue() {
if (isEmpty()) {
return false;
}
p_start++;
return true;
};
int Front() {
return data[p_start];
};
bool isEmpty() {
return p_start >= data.size();
}
};
But this has drawbacks. Memory is wasted every time we dequeue.
Thus, need a circular queue.
Circular Queue
fixed-size array, 2 pointers indicating head and tail. Goal is to reuse the wasted storage.
In designing a DS, it’s good to have as few attributes as possible and maintain a simple manipulation logic. Sometimes, there can be some redundancy to minimize time complexity.
Attributes:
- queue: fixed size array.
- headIndex: integer which indicates the current head element
- count: the current length. with `headIndex`, we can locate the tail element.
- capacity: max number of elements that can be held in the queue. With this, we reduce TC for calling len(queue).
class MyCircularQueue {
private:
vector<int> data;
int head;
int tail;
int size;
public:
MyCircularQueue(int k) {
data.resize(k);
head = -1;
tail = -1;
size = k;
}
bool enQueue(int value) {
if (isFull()) {
return false;
}
if (isEmpty()) {
head = 0;
}
tail = (tail + 1) % size;
data[tail] = value;
return true;
}
bool deQueue() {
if (isEmpty()) {
return false;
}
if (head == tail) {
head = -1;
tail = -1;
return true;
}
head = (head + 1) % size;
return true;
}
int Front() {
if (isEmpty()) {
return -1;
}
return data[head];
}
int Rear() {
if (isEmpty()) {
return -1;
}
return data[tail];
}
bool isEmpty() {
return head == -1;
}
bool isFull() {
return ((tail + 1) % size) == head;
}
};
Built In Queue C++
use stl queue in practice.
#include <queue>
int main() {
queue<int> q;
q.push(5);
if (q.empty()) {}
q.pop();
q.front() ; get first element
q.back() ; get last element
q.size() ; get size
}