STL 优先队列的自定义比较函数与 sort() 等泛型算法的自定义比较函数的区别

Posted 大峰子的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STL 优先队列的自定义比较函数与 sort() 等泛型算法的自定义比较函数的区别相关的知识,希望对你有一定的参考价值。

前言


  

  最近在刷算法题,常常需要自定义比较函数作为作为函数对象送入 stl 中,遇到了下面的问题:

   泛型算法 sort() 的比较函数是这么写: 

//sort() 实现元素间关系为递增的比较函数
struct cmp{
    bool operator () (const T& a, const T& b) const
    {
        return a.x < b.x;
    }
};
//或者这样bool operator < (const T& a, const T& b) const {
    return a.x < b.x;   
}

 

  而优先队列里的比较函数是这么写:

//priority_queue 实现元素间关系为递增(实现最小堆)的比较函数
struct cmp {
   DataType x;
bool operator () (const T& a, const T& b) const { return a.x > b.x; } } //或者这样 struct T { Type_2 x; friend bool operator < (const T&a, const T& b) const { return a.x > b.x; } }

 

  同样是实现元素的递增关系即 “前驱 < 后继”,为什么一个是 “a.x < b.x”,一个是"a.x > b.x" 呢?

 

分析 sort() 


 

  先拿 sort() 进行分析,排序类的泛型算法很多,它们的 cmp 写法是相似的,这里先看一份冒泡排序实现递增关系如 <1, 2, 3 ..> 的写法,法一:当传入的 class compare 是cmp 是这个函数对象时,它会重载 () 使得 *current 、*next 进行 “<” 比较 ,如果两个元素的关系不满足 “<” ,则交换。

#include <iostream> 

template <class BidirectionalIt, class Compare> //双向迭代器
void bubble_sort(BidirectionalIt first, BidirectionalIt last, Compare comp) {
    for (; first != last; --last) 
        for (BidirectionalIt current = first, next = first; ++next != last; ++current) 
            if (!comp(*current, *next)) 
                std::swap(*current, *next); } 
}
//可以这么写
struct cmp {
    bool oprator ()(int a, int b) { 
        return a < b; 
    }
};

//或者这么写
bool cmp (int a, int b){
    return a < b;
}    

 

  一言以蔽之,就是元素将按照 cmp 中定义的逻辑关系进行排列。

  虽然 sort() 是用 快排+堆排+插入实现的而并非冒泡,但是原理是一样。

 

分析 priority_queue 


  

  现在我们再来看看优先队列。

  STL优先队列模板:priority_queue<Type, Container, Functional> ,参数分别对应的是 元素类型、容器类型、比较函数。

  注意,优先队列不是 STL 的容器,而是由 底层容器 vector/deque 实现,缺省情况下它利用 MAX-HEAP 实现,而 MAX-HEAP 是 vector 实现的完全二叉树,这样的东西称为适配器 (adapter)。

  在优先队列中默认优先级高的先出队列,具体操作是使用函数对象 less<> 重载了 “<”,所以这里优先级的高低是由 “<” 确定的,所以当我们按下面的形式写:

priority_queue<int> pQueue;

  通过操作符 < 知道元素关键字大的优先级高,此时是最大堆。若每次从堆顶取一个元素,最后得到一个序列,那么序列中元素的关系是递减的。

  我们想要让元素的关系是递增该怎么做?

   第一种办法是使用与 less<>作用相反的函数对象 greater<> 。

  第二种办法就是使用自定义比较函数,通过它实现对自定义数据类型的优先级的定义。

    2-1. 通过重载 operator < 操作符以比较元素的优先级

struct T{
    DataType key;
    friend bool operator < (const T& a, const T& b) {
        return a.key > b.key;
    }
};

    逻辑是这样:假设 a.key > b.key 为 TRUE ,由于默认是最大堆,此时优先队列会认为 a < b ,即 b 的优先级比 a 高,所以 b会被先出队,这样就实现了关键字小的元素先出队。最后输出的序列是按关键字递增的。

    2-2. 通过重载 operator () 以定义元素的优先级。

struct cmp{
    bool operator () (const Type& a, const Type& b) const {
        return a.x > b.x;
    }
};

    逻辑和 2-1 是一样的。这里重载了 () 的目的是使得 cmp 成为像 less<> 一样的函数对象(实质上是继承了 less<>) ,作为新的比较比较级的规则以 priority_queue 第三个参数的形式传入 priority_queue 中。

   

总结


 

  优先队列的“比较级”概念与”由MAX-HEAP实现“这一特性,使得自定义比较函数中需要这么写: "a.x>b.x" 。

 

延伸阅读


 

  永远让比较函数对相等的值返回false(来自Effective C++)

  C++中的 sort 使用自定义比较函数的具体运行过程是怎样的呢?

 

以上是关于STL 优先队列的自定义比较函数与 sort() 等泛型算法的自定义比较函数的区别的主要内容,如果未能解决你的问题,请参考以下文章

C++ STL中SORT的自定义比较函数?

力扣347. 前 K 个高频元素与C++stl优先队列(大小根堆)的自定义排序用法总结

力扣347. 前 K 个高频元素与C++stl优先队列(大小根堆)的自定义排序用法总结

比较器函数在优先队列 C++ STL 中如何工作?

stl-优先队列

优先队列的自定义排序方法