C++ 优先队列 priority_queue 使用篇

priority_queue (优先队列)

优先队列是一种容器适配器,采用了堆这样的数据结构,保证了第一个元素总是整个优先队列中最大的(或最小的)元素。

优先队列默认使用vector作为底层存储数据的容器,在vector上使用了堆算法将vector中的元素构造成堆的结构,所以其实我们就可以把它当作堆,凡是需要用堆的位置,都可以考虑优先队列。(所以需要先学习堆)

优先队列性质

priority_queue默认使用vector作为底层容器。

默认情况下priority_queue是大堆。

需要注意的是,priority_queue并不支持直接访问和修改除了优先级最高元素外的其他元素。如果需要对特定元素进行操作,通常需要先将其取出,然后再进行操作,最后再将其放回优先队列中。

头文件

#include <queue>

初始化

定义容器和比较函数:然后,你需要定义一个priority_queue对象,并指定元素类型和可选的比较函数(默认为std::less)。

std::priority_queue<int, std::vector<int>, std::less<int>> pq;

priority_queue的参数

priority_queue<class T,  vector<T>,  less<T>>

class T:T是优先队列中存储的元素的类型。

vector<T>,T是优先队列中存储的元素的类型。

 less<T>,T是优先队列中存储的元素的类型。并且堆顶是最大值

// priority_queue类似于 qsort,构造函数的返回值为 1 时交换位置。若构造函数相同priority_queue的堆顶和qsort的首元素相同

常用内置函数

push() 插入元素到priority_queue插入的元素会根据其优先级自动进行排序。

top() 返回优先级最高(堆顶)的元素

pop() 移除优先级最高的(堆顶)元素

empty() 检查priority_queue是否为空。

下面的代码,演示了如何使用priority_queue

#include <queue>
#include <iostream>

int main() {
    std::priority_queue<int, std::vector<int>, std::less<int>> pq;

    pq.push(3);
    pq.push(1);
    pq.push(4);
    pq.push(1);

    while (!pq.empty()) {
        std::cout << pq.top() << " ";
        pq.pop();
    }
    //输出结果为:4 3 1 1
    return 0;
}

priority_queue中的仿函数

priority_queue中,仿函数用于比较元素的优先级,并根据其返回值确定它们在队列中的位置。默认情况下,priority_queue使用std::less作为仿函数,也就是将元素按照从大到小的顺序进行排序

你可以使用不同的仿函数来改变元素的排序方式。以下是一些常见的仿函数

  • std::less<T>:对于基本数据类型和自定义类型,默认使用<运算符进行比较,按照从大到小的顺序排序。
  • std::greater<T>:对于基本数据类型和自定义类型,默认使用>运算符进行比较,按照从小到大的顺序排序。

除了上述默认提供的仿函数外,你还可以自定义仿函数来实现自定义的元素比较规则。

自定义仿函数需要满足严格弱排序的要求,即:

#include <iostream>
#include <queue>
#include <functional>

struct Person {
    std::string name;
    int age;

    Person(const std::string& n, int a) : name(n), age(a) {}
};

// 自定义仿函数
struct CompareByAge {
    bool operator()(const Person& p1, const Person& p2) const {
        return p1.age > p2.age;  // 按照年龄从小到大排序
    }
};

int main() {
    std::priority_queue<Person, std::vector<Person>, CompareByAge> pq;

    pq.push(Person("Alice", 25));
    pq.push(Person("Bob", 30));
    pq.push(Person("Charlie", 20));

    while (!pq.empty()) {
        Person p = pq.top();
        pq.pop();
        std::cout << p.name << " - " << p.age << std::endl;
    }

    return 0;
}

输出结果为:

在上面的代码中,我们定义了一个名为CompareByAge的结构体,重载了函数调用运算符operator(),按照Person对象的age成员进行比较。然后,我们将CompareByAge作为优先队列的仿函数类型,并插入3个Person对象到优先队列中。最后,我们按照自定义的排序方式依次取出元素并输出。

比较类的函数参数

less类和greater类的函数参数。

上面是less类的内部函数,less类的内部重载(),这也就是前面提到的仿函数,参数列表中有左右两个参数,左边小于右边的时候返回true,此时优先队列就是大堆。

 上面是greater类的内部函数,greater类的内部重载(),这也就是前面提到的仿函数,参数列表中有左右两个参数,左边大于右边的时候返回true,此时优先队列就是小堆。

注意:less类和greater类只能比较内置类型的数据的大小,如果用户需要比较自定义类型的数据,就需要自己定义一个比较类,并且重载()。

同时less类和greater类也具有模板参数,因为他们也是模板,所以我们如果要存储自定义类型的元素,就要将自定义类型作为模板参数传递给less类和greater类。

构造函数的参数列表 

struct cmp
{
	bool operator(const T& x, const T& y)
	{
		.....
	}
};

  • 10
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值