• STL源码剖析 | priority_queue优先队列底层模拟实现


     

     今天博主继续带来STL源码剖析专栏的第四篇博客了!
    今天带来优先队列priority_queue的模拟实现!
    话不多说,直接进入我们今天的内容!


    前言

    那么这里博主先安利一下一些干货满满的专栏啦!

    手撕数据结构https://blog.csdn.net/yu_cblog/category_11490888.html?spm=1001.2014.3001.5482这里包含了博主很多的数据结构学习上的总结,每一篇都是超级用心编写的,有兴趣的伙伴们都支持一下吧!
    算法专栏https://blog.csdn.net/yu_cblog/category_11464817.html这里是STL源码剖析专栏,这个专栏将会持续更新STL各种容器的模拟实现。

    STL源码剖析https://blog.csdn.net/yu_cblog/category_11983210.html?spm=1001.2014.3001.5482


    优先队列是什么

    优先队列的底层实现就是数据结构的堆。其中,小顶堆可以不断更新数组里的最小值,大顶堆可以不断更新数组里的最大值,push和pop自带排序功能,经常用来解决TopK问题。

    如果大家有需要数据结构堆的实现可以通过博主的传送门食用噢~

    【堆】数据结构-堆的实现【超详细的数据结构教学】https://blog.csdn.net/Yu_Cblog/article/details/124944614

    priority_queue的模拟实现

    priority_queue底层是默认适配vector的,并且默认是大顶堆。

    MyPriorityQueue.h

    1. namespace yufc {
    2. template<class T, class Container = vector, class Compare = std::less>
    3. //默认是less Compare是一个进行比较的仿函数
    4. //less -- 小堆
    5. class priority_queue {
    6. public:
    7. template<class InputIterator>
    8. priority_queue(InputIterator first, InputIterator last) {
    9. while (first != last) {
    10. //不要直接去push,push调用的是向上调整,会慢很多
    11. //先弄进数组再建堆快一点,用向下调整
    12. _con.push_back(*first);
    13. ++first;
    14. }
    15. //建堆
    16. for (int i = ((_con.size() - 1 - 1) / 2); i >= 0; i--) {
    17. adjust_down(i);
    18. }
    19. }
    20. //如果写了这个构造编译器就不会生成其它类型构造了,所以要自己写
    21. priority_queue() {}
    22. void adjust_up(size_t child) {
    23. Compare cmp;
    24. size_t parent = (child - 1) / 2;//找到父亲节点的下标
    25. while (child > 0) { //logn
    26. //if (_con[child] > _con[parent]) {
    27. //if (_con[parent] < _con[child]) {
    28. if (cmp(_con[parent],_con[child])) {
    29. std::swap(_con[child], _con[parent]);
    30. child = parent;
    31. parent = (child - 1) / 2;
    32. }
    33. else break;
    34. }
    35. }
    36. void adjust_down(size_t parent) {
    37. Compare cmp;
    38. size_t child = parent * 2 + 1;
    39. while (child < _con.size()) {
    40. //选出左右孩子中大的那个
    41. if (child + 1 < _con.size() && cmp(_con[child], _con[child + 1])) {
    42. ++child;
    43. }
    44. if (cmp(_con[parent], _con[child])) {
    45. std::swap(_con[child], _con[parent]);
    46. parent = child;
    47. child = parent * 2 + 1;
    48. }
    49. else break;//已经调整结束了,不用再调整了
    50. }
    51. }
    52. void push(const T& x) {
    53. _con.push_back(x);
    54. adjust_up(_con.size() - 1);
    55. }
    56. void pop() {
    57. std::swap(_con[0], _con[_con.size() - 1]);
    58. _con.pop_back();
    59. adjust_down(0);
    60. }
    61. const T& top() {
    62. //返回值不允许修改 -- 修改了就不是堆了
    63. return _con[0];
    64. }
    65. bool empty() const {
    66. return _con.empty();
    67. }
    68. size_t size() const {
    69. return _con.size();
    70. }
    71. private:
    72. Container _con;
    73. };
    74. }

    测试代码

    1. void test_priority_queue() {
    2. yufc::priority_queue<int,vector<int>,less<int>>pq; //底层是个堆
    3. //默认是大顶堆 -- 大的优先级高
    4. pq.push(3);
    5. pq.push(1);
    6. pq.push(2);
    7. pq.push(5);
    8. pq.push(0);
    9. pq.push(1);
    10. while (!pq.empty()) {
    11. cout << pq.top() << " ";
    12. pq.pop();
    13. }
    14. cout << endl;
    15. int a[] = { 1,3,5,7,9,2,4,6,8,0 };
    16. yufc::priority_queue<int>pq1(a, a + sizeof(a) / sizeof(int));
    17. while (!pq1.empty()) {
    18. cout << pq1.top() << " ";
    19. pq1.pop();
    20. }
    21. cout << endl;
    22. //priority_queue<int>heap(a, a + sizeof(a) / sizeof(int));//这样构造也可以
    23. //如果想控制是小的优先级高呢?
    24. //我们要调整第三个模板参数,如果想传第三个,就必须传第二个
    25. priority_queue<int,vector<int>,greater<int>>heap(a, a + sizeof(a) / sizeof(int));//这样构造也可以
    26. while (!heap.empty()) {
    27. cout << heap.top() << " ";
    28. heap.pop();
    29. }
    30. cout << endl;
    31. }

    尾声

    看到这里,相信大家对priority_queue的模拟实现已经有一定的了解了!这些容器的模拟实现,是我们掌握STL的开始,后面,博主将会给大家带来map、set、哈希等等STL容器的模拟实现,持续关注,订阅专栏,点赞收藏都是我创作的最大动力。

    (转载时请注明作者和出处。未经许可,请勿用于商业用途 )
    更多文章请访问我的主页

    @背包https://blog.csdn.net/Yu_Cblog?type=blog

  • 相关阅读:
    5.外部中断
    Linux系统之信号
    (C++17) variant的使用与union对比
    使用canvas实现时间轴上滑块的各种常用操作(仅供参考)
    Android 11 系统开发增加低电量弹窗提示 手机 平板 车载 TV 投影 通用
    【翻译】分布式系统
    angular项目启动报错
    GEE开发之Modis_NPP数据分析和获取
    鸿蒙生态融合进行时!菊风启动适配HarmonyOS NEXT,赋能原生应用实时
    1978-2021年全国及31省市农业机械总动力(万千瓦)
  • 原文地址:https://blog.csdn.net/Yu_Cblog/article/details/127617493