实现一个简单的环形队列
文章目录
一、什么是环形队列?
环形队列的定义
环形队列(Circular Queue)是一种特殊的数据结构,旨在高效地管理和利用存储空间。与传统的线性队列相比,环形队列的主要特点在于,它的队尾和队头可以在同一存储空间中循环使用,从而避免了空间浪费。
环形队列的原理
-
数据结构:
- 环形队列通常使用一个固定大小的数组来存储元素。
- 定义两个指针:
- front:指向队头元素的位置。
- rear:指向队尾元素的下一个位置。
-
容量:
- 最大容量通常比数组的大小少一个,以便能够区分空队列和满队列的状态。这是因为当
front
和rear
相等时,队列被认为是空的,而当(rear + 1) % maxSize == front
时,队列被认为是满的。
- 最大容量通常比数组的大小少一个,以便能够区分空队列和满队列的状态。这是因为当
-
入队(enqueue):
- 将新元素添加到
rear
指向的位置,然后更新rear
指针为(rear + 1) % maxSize
。如果rear
指针达到数组的末尾,它将重新回到数组的起始位置。
- 将新元素添加到
-
出队(dequeue):
- 从
front
指向的位置移除元素,然后更新front
指针为(front + 1) % maxSize
。同样,front
指针在到达数组末尾时会循环回到开头。
- 从
-
判断队列状态:
- 空队列:当
front
和rear
相等时,队列为空。 - 满队列:当
(rear + 1) % maxSize == front
时,队列满。
- 空队列:当
二、环形队列功能实现
1.构造初始化
// 构造函数,初始化队列大小
CircularQueue(int size) : maxSize(size + 1), front(0), rear(0)
{
data.resize(maxSize); // 根据最大大小调整数据存储空间
}
2.入队操作
// 入队操作
bool enqueue(const T &item)
{
if (isFull()) // 检查队列是否已满
{
throw std::runtime_error("Queue is full!"); // 抛出异常
return false; // 这个返回语句不会被执行
}
data[rear] = item; // 将新元素放入队尾
rear = (rear + 1) % maxSize; // 更新队尾指针
return true; // 入队成功
}
3.出队操作
// 出队操作
bool dequeue()
{
if (isEmpty()) // 检查队列是否为空
{
throw std::runtime_error("Queue is empty!"); // 抛出异常
return false; // 这个返回语句不会被执行
}
front = (front + 1) % maxSize; // 更新队头指针
return true; // 出队成功
}
4.查看队头元素
// 查看队头元素
T peek() const
{
if (isEmpty()) // 检查队列是否为空
{
throw std::runtime_error("Queue is empty!"); // 抛出异常
}
return data[front]; // 返回队头元素
}
5.判断队列是否为空
// 检查队列是否为空
bool isEmpty() const
{
return front == rear; // front 和 rear 相等时队列为空
}
6.判断队列是否满
// 检查队列是否已满
bool isFull() const
{
return (rear + 1) % maxSize == front; // 满的条件
}
7.返回队列当前大小
// 返回当前队列的有效元素个数
int size() const
{
return (rear - front + maxSize) % maxSize; // 计算有效元素个数
}
三、完整代码及测试
#include <iostream>
#include <vector>
#include <stdexcept>
// 环形队列模板类
template <typename T>
class CircularQueue
{
public:
// 构造函数,初始化队列大小
CircularQueue(int size) : maxSize(size + 1), front(0), rear(0)
{
data.resize(maxSize); // 根据最大大小调整数据存储空间
}
// 入队操作
bool enqueue(const T &item)
{
if (isFull()) // 检查队列是否已满
{
throw std::runtime_error("Queue is full!"); // 抛出异常
return false; // 这个返回语句不会被执行
}
data[rear] = item; // 将新元素放入队尾
rear = (rear + 1) % maxSize; // 更新队尾指针
return true; // 入队成功
}
// 出队操作
bool dequeue()
{
if (isEmpty()) // 检查队列是否为空
{
throw std::runtime_error("Queue is empty!"); // 抛出异常
return false; // 这个返回语句不会被执行
}
front = (front + 1) % maxSize; // 更新队头指针
return true; // 出队成功
}
// 查看队头元素
T peek() const
{
if (isEmpty()) // 检查队列是否为空
{
throw std::runtime_error("Queue is empty!"); // 抛出异常
}
return data[front]; // 返回队头元素
}
// 检查队列是否为空
bool isEmpty() const
{
return front == rear; // front 和 rear 相等时队列为空
}
// 检查队列是否已满
bool isFull() const
{
return (rear + 1) % maxSize == front; // 满的条件
}
// 返回当前队列的有效元素个数
int size() const
{
return (rear - front + maxSize) % maxSize; // 计算有效元素个数
}
private:
std::vector<T> data; // 存储队列元素的向量
int front, rear, maxSize; // front: 队头, rear: 队尾, maxSize: 最大容量
};
int main()
{
CircularQueue<int> cq(5); // 创建一个最大容量为5的环形队列
cq.enqueue(1); // 入队 1
cq.enqueue(2); // 入队 2
cq.enqueue(3); // 入队 3
std::cout << "Front item: " << cq.peek() << std::endl; // 输出队头元素: 1
cq.dequeue(); // 出队操作
std::cout << "Front item after dequeue: " << cq.peek() << std::endl; // 输出队头元素: 2
std::cout << "Current size: " << cq.size() << std::endl; // 输出当前队列大小: 2
return 0; // 程序结束
}
环形队列的优势
- 空间利用:环形队列能够有效利用固定大小的数组,避免了线性队列中因元素出队导致的空间浪费。
- 操作效率:入队和出队操作的时间复杂度均为 O(1),即常数时间,适合需要频繁插入和删除的场景。
适用场景
环形队列在操作系统的任务调度、数据缓冲、流媒体数据处理等场景中广泛应用。通过循环利用空间,环形队列能够高效地处理数据流和任务调度。