想写这篇博客的原因是在刷力扣的 347. 前 K 个高频元素 一题时,需要使用到优先队列priority_queue,其定义如下:

template<
    class T,
    class Container = std::vector<T>,
    class Compare = std::less<typename Container::value_type>
> class priority_queue;

第三个参数是一个可以自定义的比较类型,其必须满足二元谓词,通常可以使用如下两种方法:

  1. 使用自定义的函数对象
  2. lambda表达式
  3. 使用std::greaterstd::less(这里就不介绍这种方法了)

以题 347. 前 K 个高频元素 为例,我们要建立一个小根堆,那么代码如下:

// 方法一

using PII = pair<int, int>;

// 比较类,重载了括号运算符
struct Comp {
    bool operator()(PII& p1, PII& p2) {
        return p1.second > p2.second;
    }
};

priority_queue<PII, vector<PII>, Comp> pq;

当然,另一种方法就是使用lambda表达式,如下:

// 方法二

using PII = pair<int, int>;
auto comp = [](PII& p1, PII& p2) {
    return p1.second > p2.second;
};
// 注意这里需要使用decltype
priority_queue<PII, vector<PII>, decltype(comp)> pq;

但值得注意的是,方法二需要在C++20下才可使用。这是因为priority_queue的第三个模板形参需要的二元谓词要求可复制构造

lambda表达式即构造闭包(能够捕获作用域中的变量的无名函数对象)。而在C++20之前,闭包类型非可默认构造,闭包类型没有默认构造函数。C++20及之后,如果没有指定捕获,那么闭包类型拥有预置的默认构造函数。

而在目前,力扣中C++编译器使用的是clang17,支持C++20,故使用lambda表达式是没有问题的。