std::priority_queue + lambda表达式 + decltype
std::priority_queue
std::priority_queue 是C++标准库提供的优先队列(最大堆)实现,位于头文件
默认情况下要求元素有“小于”运算,取堆顶,返回最大值。
可以通过模板参数调整排序方式让其返回最小值,或者为自定义类型定义排序方式。
1 | template <class T, class Container = vector<T>, class Compare = less<typename Container::value_type> > |
模板参数:
T是数据类型
Container是维护最大(小)堆使用的容器类型
Compare是一个function object的类型,定义了排序方式
什么是function object?
function object是一种对象,这个对象的类重载了括号运算符,也就是 operator() ,所以这个对象可以使用 obj(…),看上去就像在调用一个function一样。
使用比较器类定义优先队列
1 |
|
使用lamda表达式排序
1 | vector<Student> students = {...}; |
使用lambda表达式的好处是让“比较方法的描述”接近sort的调用,无论从编写还是阅读都是更好的。
使用lambda表达式的坏处是,不方便复用比较方法。
使用lamda表达式定义优先队列
实际上priority_queue有一个构造函数,可以传递一个比较对象,如果不传递就会用模板参数定义默认的比较对象。
1 | explicit priority_queue (const Compare& comp = Compare(), Container&& ctnr = Container()); |
我们可以通过构造函数参数传递一个lambda表达式定义比较方式,我们期望的定义优先队列的方式是
1 | priority_queue<Node> PQ([](const Node& a, const Node& b) { |
但是很遗憾,我们并不能这样定义,这会导致编译错误,原因是我们在模板参数仅传递了数据类型T,而没有传递Compare,因此Compare使用了默认的less
使用decltype获取lambda表达式类型
因此我们不得不传递Compare为我们定义的lambda表达式的类型,这里可以使用 decltype
关键字,这个关键字直到C++11才被引入。
1 | // 通过lambda表达式定义序 |
看上去和通过定义比较器定义优先队列似乎差不多,实际上lambda表达式的魅力在于可以访问当前上下文中的其他变量。
例如:假设我们有一个 vector<Student>
存储着学生信息,我们想定义一个存储学号的优先队列priority_queue
1 | vector<Student> students = {...}; |
如果用定义比较器类的方式则需要通过构造函数传递id2stu的引用,然后绑定给成员变量。
1 | vector<Student> students = {...}; |
本质是一样的,但是写法有些累赘。