C++priority_queue的模拟实现

C++模拟实现优先队列(priority_queue)
本文介绍了C++中的priority_queue,一种基于严格弱排序的容器适配器,其顶部元素总是最大。它类似于堆,允许随时插入元素并检索最大元素。priority_queue使用vector或deque作为底层容器,默认使用vector,并通过make_heap、push_heap和pop_heap等算法维护堆结构。

priority_queue的模拟实现

priority_queue:
1 .优先队列是一种容器适配器,根据严格的弱排序标准,它的第一个元素总是它所包含的元素中最大的

2 .此上下文类似于堆,在堆中可以随时插入元素,并且只能检索最大堆元素(优先队列中位于顶部的元素) 。

3 .优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。元素从特定容器的“尾部”弹出,其称为优先队列的顶部 。

4 .底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。容器应该可以通过随机访问迭代器访问,并支持以下操作:
empty():检测容器是否为空
size():返回容器中有效元素个数
front():返回容器中第一个元素的引用
push_back():在容器尾部插入元素
pop_back(): 在容器尾部删除元素

5 .标准容器类vector和deque满足这些需求。默认情况下,如果没有为特定的priority_queue类实例化指定容器类,则使用vector 。

6 .需要支持随机访问迭代器,以便始终在内部保持堆结构。容器适配器通过在需要时自动调用算法函数make_heap、push_heap和pop_heap来自动完成此操作 。

#include<iostream>
#include<vector>
#include<list>
#include<deque>
using namespace std;

//模拟对于自定义Date类型,priority_queue接口的模拟实现及使用

template<class T, class Con = vector<T>, class Compare = Less<T>>
class Priority_queue
{
public:
 void push(const T& x) {
  _c.push_back(x);
  shiftUp(_c.size() - 1);//最后一个孩子的位置
 }
 void pop() {
  swap(_c[0], _c[_c.size() - 1]);
  _c.pop_back();
  shiftDown(0);//
 }
 T& top() {
  return _c.front();
 }
 size_t size() const {
  return _c.size();
 }
 bool empty()const {
  return _c.empty();
 }
private:
 //向下调整,建大堆
 void shiftDown(int parent) {
  int child = 2 * parent + 1;
  while (child < _c.size()) {
   if (child + 1 < _c.size() && _com(_c[child], _c[child + 1]))
    ++child;
   if (_com(_c[parent], _c[child])){
    swap(_c[parent], _c[child]);
    parent = child;
    child = 2 * parent + 1;
   }
   else {
    break;
   }
  }
 }
 //向上调整,建大堆
 void shiftUp(int child) {
  int parent = (child - 1) / 2;
  while (child > 0) {
   if (_com(_c[parent], _c[child])) {
    swap(_c[child], _c[parent]);
    child = parent;
    parent = (child - 1) / 2;
   }
   else {
    break;
   }
  }
 }
private:
 Con _c;
 Compare _com;
};

//大于的仿函数
template <class T>
struct Greater
{
 bool operator()(const T& a, const T& b) {
  return a > b;
 }
};

//小于的仿函数
template <class T>
struct Less
{
 bool operator()(const T& a, const T& b) {
  return a < b;
 }
};

//自定义类型
class Date
{
public:
 Date(int y,int m,int d)
  :_y(y)
  , _m(m)
  , _d(d)
 {}
 //自定义类型判断大小得重载 > 和 < 运算符
 bool operator>(const Date& d)const {
  if (_y > d._y) {
   return true;
  }
  else if(_y == d._y){
   if (_m > d._m) {
    return true;
   }
   else if (_m == d._m) {
    if (_d > d._d) {
     return true;
    }
   }
  }
  return false;
 }

bool operator<(const Date& d)const {
  if (_y < d._y) {
   return true;
  }
  else if (_y == d._y) {
   if (_m < d._m) {
    return true;
   }
   else if (_m == d._m) {
    if (_d < d._d) {
     return true;
    }
   }
  }
  return false;
 }
public:
 int _y;
 int _m;
 int _d;
};

//<<对于自定义类型的重载
ostream& operator<<(ostream& cout, const Date& d){
 cout << d._y << "-" << d._m << "-" << d._d << endl;
 return cout;
}

void test1() {
 Priority_queue<Date, vector<Date>, Greater<Date>> pr;
 pr.push(Date(2011,2,2));
 pr.push(Date(2012, 12, 2));
 pr.push(Date(2011, 2, 1));
 pr.push(Date(2015, 2, 22));
 while (!pr.empty()) {
  cout << pr.top() << endl;
  pr.pop();
 }
 cout << endl;
}

int main() {
 test1();
 return 0;
}
C++ STL 中,`priority_queue` 是一个适配器容器,它基于堆结构实现,默认使用 `vector` 作为底层存储结构。然而,`priority_queue` 并没有提供直接的遍历接口,因为其对外暴露的操作仅限于访问顶部元素(最大或最小堆顶)以及插入、删除顶部元素等[^1]。 ### 1. 使用辅助容器进行遍历 一种常见的做法是将 `priority_queue` 的内容复制到一个临时容器中,然后对该容器进行遍历。例如,可以使用 `std::vector` 来接收所有元素: ```cpp #include <iostream> #include <queue> #include <vector> int main() { std::priority_queue<int> pq; pq.push(10); pq.push(30); pq.push(20); std::vector<int> temp; while (!pq.empty()) { temp.push_back(pq.top()); pq.pop(); } for (int i : temp) { std::cout << i << " "; } return 0; } ``` 此方法会破坏原始的 `priority_queue`,因此如果需要保留原始数据,可以在复制前将其拷贝到另一个临时 `priority_queue` 中进行操作[^3]。 ### 2. 使用友元函数或继承模拟实现 另一种方法是通过友元函数或者继承 `priority_queue` 来访问其内部容器。由于 `priority_queue` 的标准实现不允许直接访问内部容器,这种方法需要一定的技巧,并且可能不符合标准 C++ 的规范。例如: ```cpp #include <iostream> #include <queue> template <class T> class MyPriorityQueue : public std::priority_queue<T> { public: const std::vector<T>& getContainer() const { return this->c; } }; int main() { MyPriorityQueue<int> mpq; mpq.push(10); mpq.push(30); mpq.push(20); for (const auto& val : mpq.getContainer()) { std::cout << val << " "; } return 0; } ``` 请注意,这种方法依赖于 `priority_queue` 的具体实现细节,可能在不同的编译器或标准库实现中表现不同[^2]。 ### 3. 自定义优先队列 如果需要频繁遍历,可以考虑自行实现一个优先队列,这样可以完全控制其内部结构和访问方式。例如,可以使用 `std::make_heap` 和相关算法来维护一个堆结构: ```cpp #include <iostream> #include <vector> #include <algorithm> int main() { std::vector<int> heap = {10, 30, 20}; std::make_heap(heap.begin(), heap.end()); for (int i : heap) { std::cout << i << " "; } return 0; } ``` 这种方式允许完全的遍历操作,并且可以手动维护堆的性质[^3]。 ### 总结 尽管 `priority_queue` 不支持直接遍历,但可以通过复制到其他容器、利用继承访问内部结构或者自定义堆结构等方式实现遍历功能。每种方法都有其适用场景和限制条件,开发者应根据实际情况选择最合适的方法。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值