当前位置:   article > 正文

C++——优先级队列_c++优先队列

c++优先队列

前言:这篇文章我们继续来分享一个c++的容器——优先级队列


一.理解优先级

何为优先级一说?实际上就是有顺序的意思。

优先级队列,即有顺序的队列,是一个无需我们自己进行排序操作,在数据传入时就会由容器自己排好序的队列

先来看实例:

使用该队列,同样需要包含头文件#include<queue>

在默认情况下,优先级队列是按照从大到小排序的,而在数据结构中,也有一个能够自主排序,没错,就是从大到小的顺序,也就是大堆

那么如果想要实现小堆,又该怎么办呢?只需要增加一下模版参数

至于为什么这样写就是小堆,我们再接下来的模拟实现中进行解答。


二.基本框架

堆可以通过父节点或字节点的下标来互相找到对方的下标,所以一般情况都以数组为模板。 

  1. template <class T,class Container = vector<T>>
  2. class priority_queue
  3. {
  4. public:
  5. //向上调整
  6. void adjust_up(size_t child)
  7. {
  8. int parent = (child - 1) / 2;
  9. while (child > 0)
  10. {
  11. if (_con[child] > _con[parent])
  12. {
  13. swap(_con[child], _con[parent]);
  14. child = parent;
  15. int parent = (child - 1) / 2;
  16. }
  17. else
  18. {
  19. break;
  20. }
  21. }
  22. }
  23. //向下调整
  24. void adjust_down(size_t parent)
  25. {
  26. size_t child = parent * 2 + 1;
  27. while (child < _con.size())
  28. {
  29. if (child + 1 < _con.size() && _con[child + 1] > _con[child])
  30. {
  31. ++child;
  32. }
  33. if (_con[child] > _con[parent])
  34. {
  35. swap(_con[child], _con[parent]);
  36. parent = child;
  37. child = parent * 2 + 1;
  38. }
  39. else
  40. {
  41. break;
  42. }
  43. }
  44. }
  45. //插入
  46. void push(const T& x)
  47. {
  48. _con.push_back(x);
  49. adjust_up(_con.size() - 1);
  50. }
  51. //删除
  52. void pop()
  53. {
  54. swap(_con[_con.size() - 1], _con[0]);
  55. _con.pop_back();
  56. adjust_down(0);
  57. }
  58. //队头元素
  59. T& top()
  60. {
  61. return _con[0];
  62. }
  63. //数据个数
  64. size_t size()
  65. {
  66. return _con.size();
  67. }
  68. //判空
  69. bool empty()
  70. {
  71. return _con.empty();
  72. }
  73. private:
  74. Container _con;
  75. };

这里我们直接给出优先级队列的基本常规操作,本质就是堆的各种操作,不再一一分享。

而我们要重点分享的,就是如何切换升降序


 三.仿函数

从名字就能看出,这是一个可以冒充函数的家伙,先来看例子:

  1. template <class T>
  2. class less
  3. {
  4. public:
  5. bool operator()(const T& x, const T& y)
  6. {
  7. return x < y;
  8. }
  9. };

这段代码不难理解,在一个类中声明了一个运算符重载函数,这个函数能够进行大小比较。 

再来看这段代码,能够发现我们能够直接通过一个对象来进行两个数据之间的比较。 

这就是所谓的仿函数。 

上述仿函数是进行“小于”比较,同样我们也可以在创造一个仿函数来进行“大于”比较。

如此一来,我们便可以通过类模板将这两个仿函数用于排序比较


四.实现可选优先级

直接看代码:

  1. //小于比较
  2. template <class T>
  3. class less
  4. {
  5. public:
  6. bool operator()(const T& x, const T& y)
  7. {
  8. return x < y;
  9. }
  10. };
  11. //大于比较
  12. template <class T>
  13. class greater
  14. {
  15. public:
  16. bool operator()(const T& x, const T& y)
  17. {
  18. return x > y;
  19. }
  20. };
  21. template <class T,class Container = vector<T>,class compare = less<T>>//注意
  22. class priority_queue
  23. {
  24. //大堆
  25. public:
  26. //向上调整
  27. void adjust_up(size_t child)
  28. {
  29. compare com;//注意
  30. int parent = (child - 1) / 2;
  31. while (child > 0)
  32. {
  33. if (com(_con[parent], _con[child]))//注意
  34. {
  35. swap(_con[child], _con[parent]);
  36. child = parent;
  37. int parent = (child - 1) / 2;
  38. }
  39. else
  40. {
  41. break;
  42. }
  43. }
  44. }
  45. //向下调整
  46. void adjust_down(size_t parent)
  47. {
  48. compare com;//注意
  49. size_t child = parent * 2 + 1;
  50. while (child < _con.size())
  51. {
  52. if (child + 1 < _con.size() && com(_con[child], _con[child + 1]))//注意
  53. {
  54. ++child;
  55. }
  56. if (com(_con[parent], _con[child]))//注意
  57. {
  58. swap(_con[child], _con[parent]);
  59. parent = child;
  60. child = parent * 2 + 1;
  61. }
  62. else
  63. {
  64. break;
  65. }
  66. }
  67. }

其中less为小于比较的类,而greater为大于比较的类

而后我们通过使用类模板参数compare将两者整合在一起因为库里的优先级队列默认即为大堆,所以我们使用缺省参数默认为less

前边已经提到,使用仿函数,就是使用对应类的对象,所以我们需要创建compare类的对象com,并传入比较内容进行比较

这里要注意两个比较数据的先后位置,要按照到底是谁大于谁而传入正确的先后顺序。

 

随后就可以按照排序要求对类型进行更改,按照我们的代码方式,less为降序,greater为升序。 


总结

优先级队列的分享到这里就结束啦。

目前为止不难看出C++的这些容器的底层数据结构都是我们所学习过的,所以对于掌握容器的使用并不困难。

喜欢本篇文章记得一键三连,我们下期再见~

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

闽ICP备14008679号