队列是FIFO型结构,即先进先出,即入队(队尾添加)和出队(队首删除)。一个队列,则分首尾。如何分?两个方法:动态数组和指向队列头部的索引。入队会向队列追加一个新元素,而出队会删除第一个元素。 所以我们需要一个索引来指出起点。
#include<iostream>
#include<vector>
using namespace std;
class MyQueue{
private:
vector<int> data; //存储元素
int p_start; //起始位置的指针
public:
MyQueue(){p_start = 0;}
//往队列插入一个元素,成功返回true
bool inQueue(int x){
data.push_back(x);
return true;
}
//从队列删除一个元素,成功返回true
bool delQueue(){
if(isEmpty()){
return false;
}
p_start++;
return true;
}
//获取队列前面的元素
int Front(){return data[p_start];}
//检查队列是否为空
bool isEmpty(){
return p_start >= data.size();
}
};
int main()
{
MyQueue q;
q.inQueue(5);
q.inQueue(1);
q.inQueue(8);
if(!q.isEmpty()){
cout<<q.Front()<<endl;
}
q.delQueue();
if(!q.isEmpty()){
cout<<q.Front()<<endl;
}
q.delQueue();
if(!q.isEmpty()){
cout<<q.Front()<<endl;
}
}
上面的实现适用于添加比较少的元素,随着起始指针p_start的移动,会浪费越来越多的空间。
更有效的方法是使用循环队列。 具体来说,我们可以使用固定大小的数组
和两个指针
来指示起始位置和结束位置。 目的是重用
我们之前提到的被浪费的存储
。
在循环队列中,我们使用一个数组
和两个指针(head
和 tail
)。 head
表示队列的起始位置,tail
表示队列的结束位置。
class MyCircularQueue {
private:
vector<int> data;
int head;
int tail;
int size;
public:
//在此处初始化数据结构。将队列的大小设置为 k。
MyCircularQueue(int k) {
data.resize(k);
head = -1;
tail = -1;
size = k;
}
//将元素插入循环队列。如果操作成功,则返回 true。
bool enQueue(int value) {
if (isFull()) {
return false;
}
if (isEmpty()) {
head = 0;
}
tail = (tail + 1) % size;
data[tail] = value;
return true;
}
//从循环队列中删除元素。如果操作成功,则返回 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;
}
};
大多数流行语言都提供内置的队列库,因此无需重新发明轮子。
如前所述,队列有两个重要的操作,入队 enqueue 和出队 dequeue。 此外,我们应该能够获得队列中的第一个元素,因为应该首先处理它。
下面是使用内置队列库及其常见操作的一些示例:
#include <iostream>
#include<queue>
using namespace std;
int main() {
// 1. Initialize a queue.
queue<int> q;
// 2. Push new element.
q.push(5);
q.push(13);
q.push(8);
q.push(6);
// 3. Check if queue is empty.
if (q.empty()) {
cout << "Queue is empty!" << endl;
return 0;
}
// 4. Pop an element.
q.pop();
// 5. Get the first element.
cout << "The first element is: " << q.front() << endl;
// 6. Get the last element.
cout << "The last element is: " << q.back() << endl;
// 7. Get the size of the queue.
cout << "The size is: " << q.size() << endl;
}