C++常用语法——priority_queue部分(完善中)

1、priority_queue是什么

priority_queue属于容器适配器,它也就是我们常常提到的优先级队列

另外在一些算法相关的书籍中提到的大顶堆、小顶堆等数据结构也是指priority_queue

priority_queue定义了一个元素有序排列的队列,默认队列头部的元素优先级最高

因为它是一个队列,所以只能访问第一个元素,这也意味着优先级最高的元素总是第一个被处理

但是如何定义“优先级”完全取决于我们自己(如果一个优先级队列记录的是医院里等待接受急救的病人,那么病人病情的严重性就是优先级)


2、priority_queue的代码原型

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

可以看到,priority_queue模板有3个参数:

  • 第一个参数是存储对象的类型

  • 第二个参数是存储元素的底层容器(可缺省,默认使用vector)

  • 第三个参数是函数对象,它定义了一个用来决定元素顺序的断言(可缺省,默认大顶堆)模板参数的中的函数对象可以不写()

其中第二个参数存储元素的底层容器可以是满足priority_queue所需要操作的任何底层容器,一般来说,可选vector和deque

其中第三个参数决定元素优先级的函数对象可以是标准库中定义好的一些比较仿函数,也可以是自定义的其他仿函数。其中默认是标准库中提供的less<T>函数——对应获得一个大顶堆,如果想获得一个小顶堆,可以改用greater<T>函数


3、priority_queue的初始化

创建空的priority_queue

//默认是一个使用vec作为底层容器的大顶堆
std::priority_queue<std::string> words;

使用初值列表初始化

初始化列表中的序列可以来自于任何容器,并且不需要有序,优先级队列会对它们进行排序

大顶堆
std::string wrds[] { "one", "two", "three", "four"};
std::priority_queue<std::string> words { std::begin(wrds),std:: end(wrds)};
// "two" "three" "one" "four"(字母顺序的大顶堆)
小顶堆
std:: string wrds[] {"one", "two", "three", "four"};
std::priority_queue<std::string, std::vector<std::string>,std: :greater<std::string>> words1 {std::begin (wrds) , std:: end (wrds) };
//"four" "one" "three" "two"(字母顺序的小顶堆)

拷贝构造

std::priority_queue<std::string> copy_words {words}; // copy of words

使用vector/deque容器初始化(调用构造函数)

priority_queue构造函数的第一个参数是一个用来对元素排序的函数对象,第二个参数是一个提供初始元素的容器

注意这里说的是priority_queue的构造函数的参数,而不是模板参数(前面第2部分priority_queue的代码原型中讲的是priority_queue的模板参数)

大顶堆
//在队列中用函数对象对vector元素的副本排序
//values中元素的顺序没有变,但是优先级队列中的元素顺序变为:56 54 24 22 21 12 3
std::vector<int> values{21, 22, 12, 3, 24, 54, 56};
std::priority_queue<int> numbers {std::less<int>(),values};
小顶堆
//这里要注意,不仅模板参数中需要指出比较函数std::greater<int>,构造函数也需要指出参数std::greater<int>()
//而且,构造函数的函数对象参数需要加()
std::priority_queue<int, std::vector<int>,std::greater<int>> numbersl {std::greater<int>(), values};

4、priority_deque的操作

push()函数——添加元素

  • push(const T& obj):将obj的副本放到容器的适当位置,这通常会包含一个排序操作

  • push(T&& obj):将obj放到容器的适当位置,这通常会包含一个排序操作

emplace()函数——添加元素

  • emplace(T constructor a rgs...):通过调用传入参数的构造函数,在序列的适当位置构造一个T对象

  • 为了维持优先顺序,通常需要一个排序操作

  • 作用与push()函数类似,但是效率比push高一些

top()函数——访问堆顶

empty()函数——队列为空则返回true

size()函数——返回队列中元素个数

pop()函数——弹出元素

priority_queue没有迭代器,如果想要访问全部的元素,比如说,列出或复制它们,需要使用pop()函数来访问

但是pop()函数会导致元素弹出队列,遍历之后会将队列清空

如果想在进行这样的操作后,还能保存它的元素,需要先把它复制一份

std::priority_queue<std::string> words_copy {words}; // A copy for output
while (!words_copy.empty()){
    std:: cout << words_copy.top () <<" ";
    words_copy.pop();
}
std::cout << std::endl;

swap()函数——交换队列元素

和参数中队列的元素进行交换,所包含对象的类型必须相同

swap(priority_queue<T>& other):

5、高级用法

自定义排序函数

以下示例出自leetcode:347题“前K个高频元素” 官方解法

bool cmp(pair<int, int>& m, pair<int, int>& n){
	return m.second > n.second;
}
//其中decltype进行类型推导,推导函数对象的类型
priority_queue<pair<int, int>, vector<pair<int, int>>, decltype(&cmp)> q(cmp);
posted @ 2021-08-31 17:35  Yu_tiann  阅读(462)  评论(1编辑  收藏  举报