STL 之 queue、priority_queue 源代码剖析

本文详细介绍了STL中的队列(queue)和优先队列(priority_queue)的实现原理与使用方法。探讨了队列如何通过底层容器实现先进先出(FIFO)的数据操作,并分析了优先队列如何借助堆数据结构实现高效的插入与删除最大(或最小)元素的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
* Copyright (c) 1994
* Hewlett-Packard Company
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Hewlett-Packard Company makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
*
* Copyright (c) 1996,1997
* Silicon Graphics Computer Systems, Inc.
*
* Permission to use, copy, modify, distribute and sell this software
* and its documentation for any purpose is hereby granted without fee,
* provided that the above copyright notice appear in all copies and
* that both that copyright notice and this permission notice appear
* in supporting documentation. Silicon Graphics makes no
* representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*/
/* NOTE: This is an internal header file, included by other STL headers.
* You should not attempt to use it directly.
*/
#ifndef __SGI_STL_INTERNAL_QUEUE_H
#define __SGI_STL_INTERNAL_QUEUE_H
__STL_BEGIN_NAMESPACE
#ifndef __STL_LIMITED_DEFAULT_TEMPLATES
template <class T, class Sequence = deque<T> >
#else
template <class T, class Sequence>
#endif
class queue {
friend bool operator== __STL_NULL_TMPL_ARGS (const queue& x, const queue& y);
friend bool operator< __STL_NULL_TMPL_ARGS (const queue& x, const queue& y);
public:
typedef typename Sequence::value_type value_type;
typedef typename Sequence::size_type size_type;
typedef typename Sequence::reference reference;
typedef typename Sequence::const_reference const_reference;
protected:
Sequence c; // 底層容器
public:
// 下面全然利用 Sequence c 的操作。完毕 queue 的操作。
bool empty() const { return c.empty(); }
size_type size() const { return c.size(); }
reference front() { return c.front(); }
const_reference front() const { return c.front(); }
reference back() { return c.back(); }
const_reference back() const { return c.back(); }
// deque 是兩頭可進出,queue 是末端進,前端出(所以先進者先出)。

void push(const value_type& x) { c.push_back(x); } void pop() { c.pop_front(); } }; template <class T, class Sequence> bool operator==(const queue<T, Sequence>& x, const queue<T, Sequence>& y) { return x.c == y.c; } template <class T, class Sequence> bool operator<(const queue<T, Sequence>& x, const queue<T, Sequence>& y) { return x.c < y.c; } #ifndef __STL_LIMITED_DEFAULT_TEMPLATES /* 預設情況下 priority_queue 係利用 vector 完毕一個 max-heap,後者乃為一個以 array(或 vector)表現的二元樹。其條件是,必須為全然樹(complete tree,此為 結構特性),且每個節點值都大於或等於其任一子節點值(此為次序特性)。因此根節點為 最大值。Max-heap 適用於 priority_queue 所需特性。

*/ template <class T, class Sequence = vector<T>, class Compare = less<typename Sequence::value_type> > #else template <class T, class Sequence, class Compare> #endif class priority_queue { public: typedef typename Sequence::value_type value_type; typedef typename Sequence::size_type size_type; typedef typename Sequence::reference reference; typedef typename Sequence::const_reference const_reference; protected: Sequence c; // 底層容器 Compare comp; // 元素大小比较標準 public: priority_queue() : c() {} explicit priority_queue(const Compare& x) : c(), comp(x) {} // 下面用到的make_heap(), push_heap(), pop_heap()都是泛型演算法 // 注意,任一個建構式都立马於底層容器內產生一個implicit representation heap。

#ifdef __STL_MEMBER_TEMPLATES template <class InputIterator> priority_queue(InputIterator first, InputIterator last, const Compare& x) : c(first, last), comp(x) { make_heap(c.begin(), c.end(), comp); } template <class InputIterator> priority_queue(InputIterator first, InputIterator last) : c(first, last) { make_heap(c.begin(), c.end(), comp); } #else /* __STL_MEMBER_TEMPLATES */ priority_queue(const value_type* first, const value_type* last, const Compare& x) : c(first, last), comp(x) { make_heap(c.begin(), c.end(), comp); } priority_queue(const value_type* first, const value_type* last) : c(first, last) { make_heap(c.begin(), c.end(), comp); } #endif /* __STL_MEMBER_TEMPLATES */ bool empty() const { return c.empty(); } size_type size() const { return c.size(); } const_reference top() const { return c.front(); } void push(const value_type& x) { __STL_TRY { // push_heap 是泛型演算法。先利用底層容器的 push_back() 將新元素 // 推入末端。再重排 heap。見C++ Primer p.1195。

c.push_back(x); push_heap(c.begin(), c.end(), comp); // push_heap 是泛型演算法 } __STL_UNWIND(c.clear()); } void pop() { __STL_TRY { // pop_heap 是泛型演算法,從 heap 內取出一個元素。它並不是真正將元素 // 彈出。而是重排 heap,然後再以底層容器的 pop_back() 取得被彈出 // 的元素。

見C++ Primer p.1195。

pop_heap(c.begin(), c.end(), comp); c.pop_back(); } __STL_UNWIND(c.clear()); } }; // no equality is provided __STL_END_NAMESPACE #endif /* __SGI_STL_INTERNAL_QUEUE_H */ // Local Variables: // mode:C++ // End:


### 一、queuepriority_queue 的定义 `queue` 是一种 FIFO(First In First Out,先进先出)的线性数据结构[^4]。这意味着最早进入队列的元素会最先被移除。 而 `priority_queue` 则是一种基于堆的数据结构,其核心特点是:无论何时插入新元素,队列头部总是具有最高优先级的元素[^1]。默认情况下,`priority_queue` 使用最大堆来实现,因此顶部元素是当前队列中最大的值。 --- ### 二、queuepriority_queue 的主要区别 #### 1. 数据存取逻辑 - **Queue**: 遵循严格的 FIFO 原则,即最先进入队列的元素会被最先取出。 - **Priority Queue**: 不遵循 FIFO 原则,而是依据元素的优先级决定哪个元素应被最先取出。通常来说,优先级最高的元素会在队首位置[^4]。 #### 2. 底层实现机制 - **Queue**: 默认使用双端队列 (`deque`) 实现,支持两端操作 (front 和 back)[^4]。 - **Priority Queue**: 默认使用向量 (`vector`) 结合堆算法实现,底层是一个完全二叉树表示的最大堆或最小堆[^3]。 #### 3. 插入与删除效率 - 对于普通的 `queue`,插入和删除的时间复杂度均为 O(1),因为只需要调整队尾或队头指针即可完成相应操作。 - 而对于 `priority_queue`,由于每次都需要维护堆性质,插入时间为 O(log n),弹出同样为 O(log n) 时间复杂度[^5]。 #### 4. 自定义比较函数的支持程度 - **Queue**: 不允许自定义排序规则,仅能按固定顺序依次进出。 - **Priority Queue**: 支持通过模板参数传递自定义比较器(如 `std::greater<T>` 或其他用户定义的谓词类),从而灵活改变优先级判断标准[^5]。 --- ### 三、queuepriority_queue 的典型应用场景 #### 1. Queue 的适用场景 当需要严格按照时间序列处理任务或者消息时可以考虑使用普通队列。例如: - CPU调度中的轮转法(Round Robin Scheduling) - 广度优先搜索(BFS) ```cpp #include <iostream> #include <queue> using namespace std; void demoQueue() { queue<int> q; q.push(1); q.push(2); cout << "Front item: " << q.front() << endl; // 输出 Front item: 1 q.pop(); cout << "After pop, front item: " << q.front() << endl; // After pop, front item: 2 } ``` #### 2. Priority Queue 的适用场景 如果希望根据某些特定条件动态安排待办事项,则更适合选用带权重管理功能的优先权队列。比如: - Dijkstra算法求解单源最短路径问题; - Huffman编码构建最优前缀码表过程等等。 下面展示了一个简单的例子演示如何利用 C++ STL 提供的功能创建一个小顶堆: ```cpp #include <functional> #include <queue> #include <vector> #include <iostream> using namespace std; void demoPriorityQueue(){ vector<int> nums = {2, 9, 1, 6, 7, 4 ,0}; priority_queue<int,vector<int>,greater<int>> minHeap(nums.begin(),nums.end()); while(!minHeap.empty()){ cout<<minHeap.top()<<" "; minHeap.pop(); } } // Output will be : 0 1 2 4 6 7 9 ``` --- ### 四、总结对比表格 | 特性 | Queue | Priority Queue | |---------------------|----------------------------------|------------------------------------| | 存储模型 | FIFO | 根据优先级 | | 底层实现 | deque | vector | | 插入/删除复杂度 | O(1)/O(1) | O(log N)/O(log N) | | 是否可定制排序 | 否 | 可 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值