C++中的priority_queue笔记

3 篇文章 1 订阅

C++中的priority_queue笔记

关于priority_queue

在之前学习数据结构与算法的时候,对于优先序列只是听说。刚好最近有需要用到它的地方。可发现自己知之甚少。在查阅相关博客后,只是对于其用法有个大概的了解。即

在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出 (first in, largest out)的行为特征。

而对于序列中的元素在插入到弹出的过程中,发生了什么不是很清楚。因此,这次花了点时间看了下相关源码。
其中英文介绍为

Priority queues are a type of container adaptors, specifically designed such that its first element is always the greatest of the elements it contains, according to some strict weak ordering criterion.
This context is similar to a heap, where elements can be inserted at any moment, and only the max heap element can be retrieved (the one at the top in the priority queue).
Priority queues are implemented as container adaptors, which are classes that use an encapsulated object of a specific container class as its underlying container, providing a specific set of member functions to access its elements. Elements are popped from the “back” of the specific container, which is known as the top of the priority queue.
大意是:优先队列像heap一样随时可以插入元素,并且总是保证顶端元素是最大的(大顶堆)这里总是保证顶端元素最大,是在默认排序谓词为less<T>的前提下。我们可以通过设置不同的谓词来实现不同的优先级排序。对于同一数据类型,我们也可以提供不同的规则来划分不一样的优先级。(参考后面的代码示例)

并且,还要求其底层容器支持

  1. 具有随机访问迭代器,list,stack,queue等排除
  2. 能够实现以下几种操作
    • empty()
    • size()
    • front()
    • push_back()
    • pop_back()

所以,标准容器库里面就只有vectordeque才符合这一要求。事实上,priority_queue在创建对象的时候,所选容器类型也只有这两个。并且默认为vector<T>(见下源码)

template <class T, class Container = vector<T>,
	class Compare = less<typename Container::value_type> > class priority_queue;
/*
*T:插入元素类型
*Container:内部数据的存储位置,默认为vector
*Compare:二元谓词,规定插入的元素如何进行优先级划分。默认通过仿函数`less<T>`进行划分
*/

这里菜鸡的我想顺便记录下less<T>作用

template <class T> struct less {
  bool operator() (const T& x, const T& y) const {return x<y;}
  typedef T first_argument_type;
  typedef T second_argument_type;
  typedef bool result_type;
};
/*参数类型:T
*返回第一个值是否小于第二个值的对比结果
*作用:按照从小到大进行排序
*参考网址:http://www.cplusplus.com/reference/functional/less/
*/

// 代码示例
// less example
#include <iostream>     // std::cout
#include <functional>   // std::less
#include <algorithm>    // std::sort, std::includes

int main () {
  int foo[]={10,20,5,15,25};
  int bar[]={15,10,20};
  std::sort (foo, foo+5, std::less<int>());  // 5 10 15 20 25
  std::sort (bar, bar+3, std::less<int>());  //   10 15 20
  if (std::includes (foo, foo+5, bar, bar+3, std::less<int>()))
    std::cout << "foo includes bar.\n";
  return 0;
}

因此,当我们创建一个优先队列时,可以根据需要传入不同的参数以实现不同的功能

//优先队列创建代码示例
#include<queue> //仍然是放在queue头文件里面

priority_queue<int> a; //单纯地声明一个整型数据的优先队列
//等同于 priority_queue<int, vector<int>, less<int> > a;
priority_queue<int, vector<int>, greater<int> > c;  //这样就是小顶堆
priority_queue<string> b; //单纯地声明一个string类型的优先队列
priority_queue<Person, vector<Person>, Compare> d; 
//此处,队列元素为自定义数据类型,因此需要定义相对应的二元谓词
//Reference:https://www.cnblogs.com/dayq/p/11939324.html

最后,根据对不同的数据类型进行测试,加深理解

//常见数据类型int
cout << "priority_queue test2: " << endl;
    priority_queue<int> pq2;
    pq2.push(3);
    pq2.push(2);
    pq2.push(4);
    while(!pq2.empty()){
        cout << pq2.top() << endl;
        pq2.pop();
    }
/*
*结果:4,3,2
*分析:因为默认从小到大的堆排序。pop()返回顶端最大元素
*/

对于常见数据类型string

cout << "priority_queue test3: " << endl;
    priority_queue<string> pq3;
    pq3.push("xiaoming");
    pq3.push("xiaozhang");
    pq3.push("awei");
    while(!pq3.empty()){
        cout << pq3.top() << endl;
        pq3.pop();
    }

/*
*没什么好说的,结果分别是:xiaozhang、xiaoming、awei
*/
//改变排序规则时
priority_queue<string, vector<string>, greater<string>>  pq3;
//结果为:awei、xiaozhang、xiaoming

值得关注的可能是自定义数据类型。而我们有两种方式定义我们的数据类型class以及struct

//数据类型定义
struct Person{
    int m_age;
    int m_height;
    string m_name;
    Person() :m_age(), m_height(), m_name(){} //无参数的构造函数数组初始化时调用
    Person(int age, int height, string str) : m_age(age), m_height(height), m_name(str){}//有参构造
};
//优先级划分准则
struct Compare{
    bool operator()(const Person &p1, const Person &p2) {
        if (p1.m_age > p2.m_age) return true;
        else {
            return p1.m_height > p2.m_height;
        }
    }
};

需要注意的是:这里的优先级划分必须是二元谓词,因此定义的函数是不可行。其次,通过class定义的谓词也无法工作。这是我所学习到的一点。struct定义的数据类型,要通过struct的方式定义谓词

\*
* 代码测试:
* 首先可以分析一下,对于每一次通过push传入的Person对象,都会根据其年龄以及身高来进行
* 从大到小的排序。也就是年龄最小的Person会在最上面,第一个被pop()出来。
* 当年龄相等时,身高较矮的在顶端
*\
cout << "priority_queue test1: " << endl;
    Person p1(24, 185, "xiaoming");
    Person p2(24, 165, "xiaoli");
    Person p3(23, 165, "xiaozhu");
    priority_queue<Person, vector<Person>, Compare> pq;
    pq.push(p1);
    pq.push(p2);
    pq.push(p3);
    while(!pq.empty()){
    cout << "name:" << pq.top().m_name << "age:" << pq.top().m_age 
    << "height:" << pq.top().m_height << endl;
    pq.pop();
    }
/*
* 预测结果:xiaozhu、xiaoli、xiaoming
* 真实结果:
* name:xiaozhuage:23height:165
* name:xiaoliage:24height:165
* name:xiaomingage:24height:185
*/

补充

大顶堆和小顶堆傻傻分不清楚?
我最开始也是很懵。以下面的代码为例

priority_queue<int> q; 
//这里默认是通过less<T>仿函数来定义优先级

按照我们在sort()时传入该仿函数,会实现从小到大排序。
对于vector<int> testV = {1,2,4,2,5,6};排序后的结果为1, 2, 2, 4, 5, 6。结果,在插入优先队列q的过程中,这个又被称为大顶堆。是为什么?
这就和priority_queue的成员函数有关系了。它的pop()不是像队列意向pop_front();而是像stack一样,pop() from top()
因此,我们插入队列中的顺序依旧是1, 2, 2, 4, 5, 6。但是先出来的顺序是6,5,4,3,2,2,1
同样的,

priority_queue<int, vector<int>, greater<int> > c;  
//这样就是小顶堆

较大的元素具有最高的优先级,被插入到priority_queue的头部。却因为只能pop() from top()。就称为小顶堆。
个人愚见,一点帮助自己理解的想法而已

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值