C++ STL priority_queue自定义排序实现方法详解

前面讲解 priority_queue 容器适配器时,还遗留一个问题,即当 <function> 头文件提供的排序方式(std::less<T> 和 std::greater<T>)不再适用时,如何自定义一个满足需求的排序规则。

首先,无论 priority_queue 中存储的是基础数据类型(int、double 等),还是 string 类对象或者自定义的类对象,都可以使用函数对象的方式自定义排序规则。例如:

#include<iostream>
#include<queue>
using namespace std;
//函数对象类
template <typename T>
class cmp
{
public:
  //重载 () 运算符
  bool operator()(T a, T b)
  {
    return a > b;
  }
};
int main()
{
  int a[] = { 4,2,3,5,6 };
  priority_queue<int,vector<int>,cmp<int> > pq(a,a+5);
  while (!pq.empty())
  {
    cout << pq.top() << " ";
    pq.pop();
  }
  return 0;
}

运行结果为:
2 3 4 5 6

注意,C++ 中的 struct 和 class 非常类似,前者也可以包含成员变量和成员函数,因此上面程序中,函数对象类 cmp 也可以使用 struct 关键字创建:

struct cmp
{
  //重载 () 运算符
  bool operator()(T a, T b)
  {
    return a > b;
  }
};

可以看到,通过在 cmp 类(结构体)重载的 () 运算符中自定义排序规则,并将其实例化后作为 priority_queue 模板的第 3 个参数传入,即可实现为 priority_queue 容器适配器自定义比较函数。

除此之外,当 priority_queue 容器适配器中存储的数据类型为结构体或者类对象(包括 string 类对象)时,还可以通过重载其 > 或者 < 运算符,间接实现自定义排序规则的目的。

注意,此方式仅适用于 priority_queue 容器中存储的为类对象或者结构体变量,也就是说,当存储类型为类的指针对象或者结构体指针变量时,此方式将不再适用,而只能使用函数对象的方式。

要想彻底理解这种方式的实现原理,首先要搞清楚 std::less<T> 和 std::greater<T> 各自的底层实现。实际上,<function> 头文件中的 std::less<T> 和 std::greater<T> ,各自底层实现采用的都是函数对象的方式。比如,std::less<T> 的底层实现代码为:

template <typename T>
struct less {
  //定义新的排序规则
  bool operator()(const T &_lhs, const T &_rhs) const {
    return _lhs < _rhs;
  }
};

std::greater<T> 的底层实现代码为:

template <typename T>
struct greater {
  bool operator()(const T &_lhs, const T &_rhs) const {
    return _lhs > _rhs;
  }
};

可以看到,std::less<T> 和 std::greater<T> 底层实现的唯一不同在于,前者使用 < 号实现从大到小排序,后者使用 > 号实现从小到大排序。

那么,是否可以通过重载 < 或者 > 运算符修改 std::less<T> 和 std::greater<T> 的排序规则,从而间接实现自定义排序呢?答案是肯定的,举个例子:

#include<queue>
#include<iostream>
using namespace std;
class node {
public:
  node(int x = 0, int y = 0) :x(x), y(y) {}
  int x, y;
};
//新的排序规则为:先按照 x 值排序,如果 x 相等,则按 y 的值排序
bool operator < (const node &a, const node &b) {
  if (a.x > b.x) return 1;
  else if (a.x == b.x)
    if (a.y >= b.y) return 1;
  return 0;
}
int main() {
  //创建一个 priority_queue 容器适配器,其使用默认的 vector 基础容器以及 less 排序规则。
  priority_queue<node> pq;
  pq.push(node(1, 2));
  pq.push(node(2, 2));
  pq.push(node(3, 4));
  pq.push(node(3, 3));
  pq.push(node(2, 3));
  cout << "x y" << endl;
  while (!pq.empty()) {
    cout << pq.top().x << " " << pq.top().y << endl;
    pq.pop();
  }
  return 0;
}

输出结果为:
x y
1 2
2 2
2 3
3 3
3 4

可以看到,通过重载 < 运算符,使得 std::less<T> 变得适用了。
读者还可以自行尝试,通过重载 > 运算符,赋予 std::greater<T> 和之前不同的排序方式。

当然,也可以以友元函数或者成员函数的方式重载 > 或者 < 运算符。需要注意的是,以成员函数的方式重载 > 或者 < 运算符时,该成员函数必须声明为 const 类型,且参数也必须为 const 类型,至于参数的传值方式是采用按引用传递还是按值传递,都可以(建议采用按引用传递,效率更高)。

例如,将上面程序改为以成员函数的方式重载 < 运算符:

class node {
public:
  node(int x = 0, int y = 0) :x(x), y(y) {}
  int x, y;
  bool operator < (const node &b) const{
    if ((*this).x > b.x) return 1;
    else if ((*this).x == b.x)
      if ((*this).y >= b.y) return 1;
    return 0;
  }
};

同样,在以友元函数的方式重载 < 或者 > 运算符时,要求参数必须使用 const 修饰。例如,将上面程序改为以友元函数的方式重载 < 运算符。例如:

class node {
public:
  node(int x = 0, int y = 0) :x(x), y(y) {}
  int x, y;
  friend bool operator < (const node &a, const node &b);
};
//新的排序规则为:先按照 x 值排序,如果 x 相等,则按 y 的值排序
bool operator < (const node &a, const node &b){
  if (a.x > b.x) return 1;
  else if (a.x == b.x)
    if (a.y >= b.y) return 1;
  return 0;
}

总的来说,以函数对象的方式自定义 priority_queue 的排序规则,适用于任何情况;而以重载 > 或者 < 运算符间接实现 priority_queue 自定义排序的方式,仅适用于 priority_queue 中存储的是结构体变量或者类对象(包括 string 类对象)。

到此这篇关于C++ STL priority_queue自定义排序实现方法详解的文章就介绍到这了,更多相关STL priority_queue自定义排序内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • STL priority_queue(优先队列)详解

    构造,析构 priority_queue() //默认构造函数,生成一个空的排序队列 priority_queue(const queue&); //拷贝构造函数 priority_queue(const Compare& comp); //构造生成一个空的priority_queue对象, //使用comp作为priority_queue的comparison priority_queue(const value_type* first, const value_type* last);

  • C++ STL priority_queue自定义排序实现方法详解

    前面讲解 priority_queue 容器适配器时,还遗留一个问题,即当 <function> 头文件提供的排序方式(std::less<T> 和 std::greater<T>)不再适用时,如何自定义一个满足需求的排序规则. 首先,无论 priority_queue 中存储的是基础数据类型(int.double 等),还是 string 类对象或者自定义的类对象,都可以使用函数对象的方式自定义排序规则.例如: #include<iostream> #in

  • Java实现自定义Excel数据排序的方法详解

    目录 1.引入jar包 2.自定义排序 通常,我们可以在Excel中对指定列数据执行升序或者降序排序,排序时可依据单元格中的数值.单元格颜色.字体颜色或图标等.在需要自定义排序情况下,我们也可以自行根据排序需要编辑数据排列顺序.本文,将通过Java应用程序来实现如何自定义排序. 1.引入jar包 使用jar包:Spire.Xls.jar version: 12.8.4 导入方法1:手动下载jar到本地,解压,然后找到lib文件夹下的Spire.Xls.jar文件.然后在IDEA中打开“Proje

  • Jsp自定义标签和方法详解

    Jsp自定义标签和方法详解 首先是要有一个标签处理类,标签处理类可以直接实现Tag接口,也可以继承Java中已经实现了的TagSupport这个类,TagSupport也是继承自Tag接口的,它内部已经对Tag接口进行了实现,一般是继承TagSupport类,之后是重写父类的doStartTag和doEndTag方法, 对于开始标签来说返回值主要有EVAL_BODY_INCLUDE和SKIP_BODY,前者表示执行标签体,后者表示略过标签体: 对于结束标签的返回值主要有两种EVAL_PAGE和S

  • 对python 自定义协议的方法详解

    前面说到最近在写python的一些东西,然后和另外一位小伙伴定义了协议,然后昨天我有一部分东西没理解对,昨天上午我自己重写了一遍接收和发送的全部逻辑,昨天下午补了压力测试的脚本,自测没问题之后告知联调的小伙伴. 结果上午还是出了一点问题,然后我们两对代码,他写了一个python的实现.还好最后我这边没问题.(我也害怕是我这边出问题啊,所以我自己的代码都自己检查了好几遍) 简单放一下他的实现: import struct import ctypes class E(Exception): def

  • JavaScript实现拖拽排序的方法详解

    目录 实现原理概述 代码实现 完整代码实现 可拖拽排序的菜单效果大家想必都很熟悉,本次我们通过一个可拖拽排序的九宫格案例来演示其实现原理. 先看一下完成效果: 实现原理概述 拖拽原理 当鼠标在[可拖拽小方块](以下简称砖头)身上按下时,开始监听鼠标移动事件 鼠标事件移动到什么位置,砖头就跟到什么位置 鼠标抬起时,取消鼠标移动事件的监听 排序原理 提前定义好9大坑位的位置(相对外层盒子的left和top) 将9大砖头丢入一个数组,以便后期通过splice方法随意安插和更改砖头的位置 当拖动某块砖头

  • Java实现ArrayList排序的方法详解

    目录 简介 法1:JDK8的stream 法2:Comparator#compare() 法3:Comparable#compareTo() 简介 说明 本文用示例介绍Java的ArrayList排序的方法. List排序方法 主要有三种方法(按推荐度排序): JDK8的stream Comparator#compare() Comparable#compareTo() 法1:JDK8的stream 见:一文详解Java中Stream流的使用 法2:Comparator#compare() 需求

  • Python实现在PyPI上发布自定义软件包的方法详解

    目录 1. 引言 2. 创建PyPI账号 3. 创建包名 4. 按照如下格式组织包 5. 安装 Build & Twine 6. 构建测试包 7. 上传测试包 8. 总结 1. 引言 在Python中我们经常使用pip来安装第三方Python软件包,其实我们每个人都可以免费地将自己写的Python包发布到PyPI上,供他人来通过pip进行安装. 在本文中,我们将从一步一步地详细介绍如何发布测试包. 2. 创建PyPI账号 网址: https://pypi.org/ 我们可以通过上面的链接在PyP

  • SpringBoot实现自定义事件的方法详解

    目录 简介 步骤1:自定义事件 步骤2:自定义监听器 方案1:ApplicationListener 方案2:SmartApplicationListener 步骤3:注册监听器 法1:@Component(适用于所有监听器) 法2:application.yml中添加配置 法3:启动类中注册 步骤4:发布事件 法1:注入ApplicationContext,调用其publishEvent方法 法2:启动类中发布 简介 说明 本文用实例来介绍如何在SpringBoot中自定义事件来使用观察者模式

  • Python自定义sorted排序实现方法详解

    题目 输入一个正整数数组,把数组里面的所有属猪拼接起来成为一个数打印能拼接起来的所有数字中最大/最小的那个. 思考 直观想法就是求出这个数组中所有数字的全排列,然后拼接起来,再比较大小即可,当然复杂度过高. 另一个想法,我们可以定义一个排序规则,如下:   如果两个数m,n能拼接成数字mn,nm,如果mn>nm,则m应该在n前面,反之亦然 根据这个排序规则,我们可以重新排列数组,将排列好的数组拼接起来输出即可'为了方便比较,并且防止数据溢出(比如C语言),采用字符串的方式拼接.我们很容易可以写出

  • AngularJS基于factory创建自定义服务的方法详解

    本文实例讲述了AngularJS基于factory创建自定义服务的方法.分享给大家供大家参考,具体如下: 为什么要创建自定义服务? 很简单,不想让控制器显得过于"臃肿",而且服务可复用.针对性强,每个服务对应不同的功能. 这里介绍如何使用factory创建自定义服务,并且使用他. 例子1: <!--HTML--> <div ng-controller="showTheName"> <h1 ng-bind="name"

随机推荐