当前位置:   article > 正文

C++——优先级队列(priority_queue)的使用和模拟实现_c++ priority_queue.front

c++ priority_queue.front

目录

priority_queue的使用

简单介绍

priority_queue的接口

priority_queue的模拟实现

第三个参数 Compare

日期的排序

完整代码


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来自动完成此操作。

综上所述:

优先级队列默认使用vector作为其底层存储数据的容器,在vector上又使用了堆算法将vector中元素构造成 堆的结构,因此priority_queue就是堆,所有需要用到堆的位置,都可以考虑使用priority_queue。注意: 默认情况下priority_queue是大堆。

priority_queue的接口

成员函数功能
push插入元素到队尾(并排序)
pop弹出队头元素(堆顶元素)
top访问队头元素(堆顶元素)
size获取队列中有效元素个数
empty判断队列是否为空
swap交换两个队列的内容

举例:

  1. #include<iostream>
  2. #include<queue>
  3. #include<functional>
  4. #include<vector>
  5. #include<assert.h>
  6. using namespace std;
  7. #include"priority_Queue.h"
  8. //优先级队列
  9. void test_priority_queue1()
  10. {
  11. //默认是大的优先级高 -- 默认给的仿函数是less
  12. priority_queue<int> pq;
  13. //
  14. //控制小的优先级高 -- 给一个greater的仿函数
  15. //priority_queue<int, deque<int >, greater<int>> pq;
  16. pq.push(3);
  17. pq.push(3);
  18. pq.push(7);
  19. pq.push(1);
  20. pq.push(9);
  21. while (!pq.empty())
  22. {
  23. cout << pq.top() << " ";
  24. pq.pop();
  25. }
  26. cout << endl;
  27. }

priority_queue的模拟实现

优先级队列的底层就是堆,所以大多知识我们在堆那一节课已经学过!

我们去看文档的时候会发现优先级队列priority_queue有三个参数:第一个是我们所要存放数据的类型,第二个使我们所要使用的容器,那么第三个是什么呢?

第三个参数 Compare

我们在前面就学过,优先级默认情况下是大堆,也就是数据以降序的方式存放,第三个参数的意义就是我们可以也可以让它以升序的方式存放,我们先举例说明:

  1. void test_priority_queue1()
  2. {
  3. //默认是大的优先级高并且如果我们不给容器的话会默认给vector的容器
  4. priority_queue<int> pq;
  5. pq.push(8);
  6. pq.push(2);
  7. pq.push(3);
  8. pq.push(7);
  9. pq.push(6);
  10. pq.push(5);
  11. pq.push(4);
  12. while (!pq.empty())
  13. {
  14. cout << pq.top() << " ";
  15. pq.pop();
  16. }
  17. cout << endl;
  18. }

 运行结果:

如果我们想实现升序,可以传入第三个参数greater<T>

 通过查看文档我们能发现它需要头文件<functional>

  1. void test_priority_queue1()
  2. {
  3. //传入greater后为升序
  4. priority_queue<int,vector<int>,greater<int>> pq;
  5. pq.push(8);
  6. pq.push(2);
  7. pq.push(3);
  8. pq.push(7);
  9. pq.push(6);
  10. pq.push(5);
  11. pq.push(4);
  12. while (!pq.empty())
  13. {
  14. cout << pq.top() << " ";
  15. pq.pop();
  16. }
  17. cout << endl;
  18. }

 

 那么为什么会这样呢?

其实我们所见的greater是一个仿函数。

他们的底层如下所示:

  1. template<class T>
  2. struct Less
  3. {
  4. bool operator()(const T& x, const T& y) const
  5. {
  6. return x < y;
  7. }
  8. };
  9. template<class T>
  10. struct Greater
  11. {
  12. bool operator()(const T& x, const T& y) const
  13. {
  14. return x > y;
  15. }
  16. };

这里的Less类其实就是我们在优先级队列给它第三个参数的缺省参数,这也是为什么默认是大堆的原因。

日期的排序

这里除了可以对普通的数据进行排序,其实对日期数据也可以排序!

首先我们给定一个日期类,并且重载了日期的输出的运算符和比较运算符。

  1. class Date
  2. {
  3. friend struct LessPDate;
  4. public:
  5. Date(int year = 1900, int month = 1, int day = 1)
  6. : _year(year)
  7. , _month(month)
  8. , _day(day)
  9. {}
  10. bool operator<(const Date& d)const
  11. {
  12. return (_year < d._year) ||
  13. (_year == d._year && _month < d._month) ||
  14. (_year == d._year && _month == d._month && _day < d._day);
  15. }
  16. bool operator>(const Date& d)const
  17. {
  18. return (_year > d._year) ||
  19. (_year == d._year && _month > d._month) ||
  20. (_year == d._year && _month == d._month && _day > d._day);
  21. }
  22. friend ostream& operator<<(ostream& _cout, const Date& d);
  23. private:
  24. int _year;
  25. int _month;
  26. int _day;
  27. };
  28. ostream& operator<<(ostream& _cout, const Date& d)
  29. {
  30. _cout << d._year << "-" << d._month << "-" << d._day << endl;
  31. return _cout;
  32. }
  1. void test_priority_queue2()
  2. {
  3. priority_queue<Date, vector<Date>> pq;
  4. //priority_queue<Date, vector<Date>,greater<Date>> pq;
  5. pq.push(Date(2022, 3, 26));
  6. pq.push(Date(2021, 10, 26));
  7. pq.push(Date(2023, 3, 26));
  8. while (!pq.empty())
  9. {
  10. cout << pq.top();
  11. pq.pop();
  12. }
  13. cout << endl;
  14. }

 当然我们也可以使用库中的greater或者我们实现的仿函数来使其实现降序。

完整代码

  1. #pragma once
  2. namespace mwb
  3. {
  4. template<class T>
  5. struct Less
  6. {
  7. bool operator()(const T& x, const T& y) const
  8. {
  9. return x < y;
  10. }
  11. };
  12. template<class T>
  13. struct Greater
  14. {
  15. bool operator()(const T& x, const T& y) const
  16. {
  17. return x > y;
  18. }
  19. };
  20. //大的优先级高 大堆
  21. template< class T, class Container = vector<T>,class Compare=Less<T> >
  22. class priority_queue
  23. {
  24. private:
  25. void adjust_up(size_t child)//向上调整算法
  26. {
  27. Compare com;
  28. size_t parent = (child - 1) / 2;
  29. while (child > 0)
  30. {
  31. //if (_con[child] > _con[parent])
  32. if(com(_con[parent],_con[child]))
  33. {
  34. swap(_con[child], _con[parent]);
  35. child = parent;
  36. parent = (child - 1) / 2;
  37. }
  38. else
  39. {
  40. break;
  41. }
  42. }
  43. }
  44. void adjust_down(size_t parent)
  45. {
  46. Compare com;
  47. size_t child = (parent * 2) + 1;
  48. //默认给左孩子
  49. while (child<_con.size())
  50. {
  51. //if (child + 1 < _con.size() && _con[child + 1] > _con[child])
  52. if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))
  53. {
  54. child++;//如果右孩子大于左孩子那么取右孩子
  55. }
  56. //if (_con[child] > _con[parent])
  57. if(com(_con[parent],_con[child]))
  58. {
  59. swap(_con[child], _con[parent]);
  60. parent = child;
  61. child = parent * 2 + 1;
  62. }
  63. else
  64. {
  65. break;
  66. }
  67. }
  68. }
  69. public:
  70. priority_queue()
  71. {}
  72. template <class InputIterator>
  73. priority_queue(InputIterator first, InputIterator last)
  74. :_con(first,last)
  75. {
  76. // 建堆
  77. for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--)
  78. {
  79. adjust_down(i);
  80. }
  81. }
  82. void push(const T& x)
  83. {
  84. _con.push_back(x);
  85. adjust_up(_con.size() - 1);
  86. }
  87. void pop()
  88. {
  89. assert(!_con.empty());//检测是否为空
  90. swap(_con[0], _con[_con.size() - 1]);//交换堆顶和堆底
  91. _con.pop_back();//尾删也就是把堆底删除
  92. adjust_down(0);//向下调整
  93. }
  94. const T& top()
  95. {
  96. return _con[0];
  97. }
  98. size_t size()
  99. {
  100. return _con.size();
  101. }
  102. bool empty()
  103. {
  104. return _con.empty();
  105. }
  106. private:
  107. Container _con;
  108. };
  109. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/355168
推荐阅读
相关标签
  

闽ICP备14008679号