1. 队列基础概念与核心特性
队列(Queue)是计算机科学中最基础且重要的数据结构之一,它遵循先进先出(FIFO)的原则。想象一下超市收银台前的队伍——先来排队的顾客会先得到服务,后来者只能排在队尾,这就是队列在现实世界中的完美体现。
队列的两个基本操作是入队(enqueue)和出队(dequeue)。入队操作在队尾添加元素,出队操作则从队首移除元素。这种特性使得队列成为处理有序任务的理想选择,比如:
- 打印机任务调度
- 消息传递系统
- 网络数据包缓冲
- 多线程编程中的任务分配
在C++中,队列可以通过多种方式实现。标准模板库(STL)提供了现成的queue容器,但理解其底层实现原理对于开发者来说至关重要。下面是一个最简单的队列接口定义:
cpp复制template <typename T>
class Queue {
public:
virtual void enqueue(const T& item) = 0;
virtual T dequeue() = 0;
virtual bool isEmpty() const = 0;
virtual size_t size() const = 0;
};
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 队列的C++实现方案对比
2.1 基于数组的静态队列实现
数组实现是最直观的方式,但需要处理"假溢出"问题——即数组未满但因头尾指针位置关系无法继续入队的情况。解决方案是使用循环数组:
cpp复制template <typename T, size_t Capacity>
class ArrayQueue {
private:
T data[Capacity];
size_t front = 0;
size_t rear = 0;
size_t count = 0;
public:
void enqueue(const T& item) {
if (count == Capacity)
throw std::runtime_error("Queue is full");
data[rear] = item;
rear = (rear + 1) % Capacity;
++count;
}
T dequeue() {
if (count == 0)
throw std::runtime_error("Queue is empty");
T item = data[front];
front = (front + 1) % Capacity;
--count;
return item;
}
// 其他接口实现...
};
这种实现的优点是内存连续、访问速度快,但缺点是需要预先确定容量,不适合动态变化的需求场景。
2.2 基于链表的动态队列实现
链表实现解决了固定容量的问题,可以动态增长:
cpp复制template <typename T>
class LinkedListQueue {
private:
struct Node {
T data;
Node* next;
Node(const T& d) : data(d), next(nullptr) {}
};
Node* head = nullptr;
Node* tail = nullptr;
size_t count = 0;
public:
~LinkedListQueue() {
while (head) {
Node* temp = head;
head = head->next;
delete temp;
}
}
void enqueue(const T& item) {
Node* newNode = new Node(item);
if (tail) {
tail->next = newNode;
} else {
head = newNode;
}
tail = newNode;
++count;
}
T dequeue() {
if (!head)
throw std::runtime_error("Queue is empty");
T item = head->data;
Node* temp = head;
head = head->next;
if (!head) tail = nullptr;
delete temp;
--count;
return item;
}
// 其他接口实现...
};
链表实现的优点是动态扩容,但每个元素需要额外的指针空间,且内存不连续可能导致缓存命中率降低。
2.3 STL queue容器深度解析
C++标准库中的queue实际上是一个容器适配器,默认使用deque作为底层容器:
cpp复制#include <queue>
#include <list>
// 默认使用deque
std::queue<int> q1;
// 也可以指定底层容器
std::queue<int, std::list<int>> q2;
STL queue的主要接口包括:
- push() - 入队
- pop() - 出队
- front() - 访问队首元素
- back() - 访问队尾元素
- empty() - 判断是否为空
- size() - 获取元素数量
3. 高级队列变体与实现
3.1 双端队列(Deque)
双端队列允许在两端进行插入和删除操作,结合了队列和栈的特性:
cpp复制template <typename T>
class Deque {
private:
struct Node {
T data;
Node* prev;
Node* next;
Node(const T& d) : data(d), prev(nullptr), next(nullptr) {}
};
Node* head = nullptr;
Node* tail = nullptr;
size_t count = 0;
public:
// 前端操作
void pushFront(const T& item) {
Node* newNode = new Node(item);
if (head) {
newNode->next = head;
head->prev = newNode;
} else {
tail = newNode;
}
head = newNode;
++count;
}
T popFront() {
if (!head)
throw std::runtime_error("Deque is empty");
T item = head->data;
Node* temp = head;
head = head->next;
if (head) head->prev = nullptr;
else tail = nullptr;
delete temp;
--count;
return item;
}
// 后端操作类似...
};
3.2 优先队列(Priority Queue)
优先队列中元素按优先级出队,而非插入顺序。通常使用堆结构实现:
cpp复制#include <vector>
#include <algorithm>
template <typename T, typename Compare = std::less<T>>
class PriorityQueue {
private:
std::vector<T> heap;
Compare comp;
void heapifyUp(size_t index) {
while (index > 0) {
size_t parent = (index - 1) / 2;
if (comp(heap[parent], heap[index])) {
std::swap(heap[parent], heap[index]);
index = parent;
} else {
break;
}
}
}
void heapifyDown(size_t index) {
size_t left, right, largest;
while (true) {
left = 2 * index + 1;
right = 2 * index + 2;
largest = index;
if (left < heap.size() && comp(heap[largest], heap[left]))
largest = left;
if (right < heap.size() && comp(heap[largest], heap[right]))
largest = right;
if (largest != index) {
std::swap(heap[index], heap[largest]);
index = largest;
} else {
break;
}
}
}
public:
void push(const T& item) {
heap.push_back(item);
heapifyUp(heap.size() - 1);
}
T pop() {
if (heap.empty())
throw std::runtime_error("Priority queue is empty");
T item = heap.front();
heap[0] = heap.back();
heap.pop_back();
if (!heap.empty()) {
heapifyDown(0);
}
return item;
}
// 其他接口...
};
4. 队列在实际项目中的应用案例
4.1 多线程任务调度
队列是多线程编程中任务分配的核心数据结构:
cpp复制#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
template <typename T>
class ThreadSafeQueue {
private:
std::queue<T> queue;
mutable std::mutex mtx;
std::condition_variable cv;
public:
void push(T item) {
std::lock_guard<std::mutex> lock(mtx);
queue.push(std::move(item));
cv.notify_one();
}
bool tryPop(T& item) {
std::lock_guard<std::mutex> lock(
