C++ 优先队列用法

Priority Queue

优先队列和一般的队列(queue)不同之处在于,优先队列里的元素具有权值,在出队列时总是权值最大的元素出列,本质是一个heap。

C++ Define

template <class Type, class Container= vector <Type>, class Compare= less <typename Container ::value_type>>
class priority_queue

Parameters

Parameterdescriptiondefault
Type队列里元素的数据类型
Container实现队列的底层容器vector
Compare两个元素值大小排序方式less

常用的Member Functions

functionDescriptionReturn
empty检查队列是否为空bool
pop队顶元素出列None
push基于operator将元素压入队列None
size返回队列元素个数unsigned int
top返回队顶元素指针reference

Requirements

  • #include<queue>
  • using namespace std;

Simple Test

empty() and push()
#include<queue>
#include<iostream>
using namespace std;
int main(){

    priority_queue <int> q;

    if(q.empty())
        cout << "the priority_queue is empty." << endl;
    q.push(20);
    if(!q.empty())
        cout << "the priority_queue is not empty." << endl;
    return 0;
}
the priority_queue is empty.
the priority_queue is not empty.
size()
#include<queue>
#include<iostream>
using namespace std;
int main(){
    priority_queue <int> q;

    cout << "q.size is " << q.size() <<endl;
    q.push(20);
    q.push(30);
    cout << "q.size is " << q.size() <<endl;
    return 0;
}
q.size is 0
q.size is 2
pop() and top()
#include<queue>
#include<iostream>
using namespace std;
int main(){
    priority_queue <int> q;

    q.push(20);
    q.push(30);
    q.push(19);
    cout << "q.size is " << q.size() << endl;
    cout << "Queue q's current top is " << q.top() << endl;
    q.pop();
    cout << "Queue q pops the top element." << endl;
    cout << "Queue q's current top is " << q.top() << endl;
    cout << "q.size is " << q.size() << endl;
    return 0;
}

q.size is 3
Queue q's current top is 30
Queue q pops the top element.
Queue q's current top is 20
q.size is 2

Advanced


元素排序

默认情况下,优先队列内部是一个大根堆,元素从大到小从队首排至队尾。

#include<queue>
#include<iostream>
using namespace std;
int main(){
    priority_queue <int> q;   //相当于 priority_queue < int, vector<int>, less<int> > q;

    q.push(20);
    q.push(30);
    q.push(7);
    q.push(5);
    q.push(12);
    q.push(0);
    q.push(32);
    cout << "output order is :";
    while( !q.empty() ){
        cout << q.top() << " ";
        q.pop();
    }
    return 0;
}
output order is :32 30 20 12 7 5 0

可以将队列声明参数Compare对应的less改成greater,此时内部大根堆变成小根堆,元素从小到大排列

output order is :0 5 7 12 20 30 32
运算符重载

在实际使用中,我们往往需要对结构体数组/类按照某一个成员的值进行排序,比如想对学生所有科目中的语文成绩进行排序,那么就需要重载比较操作符函数,即参数Compare所指向的函数。

compare可以选择greater或者less,C++ 11定义两者分别为:

less

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;
};

greater

template <class T> struct greater {
  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;
};

一般而言,排序时greater对应从大到小顺序,less对应从小到大顺序。但是在优先级队列里,less对应的是从大到小出队列,greater对应从小到大出队列,在前面示例的简单元素排序中可以看到刚好相反,这么实现的具体原因暂不探究。

在自定义结构体优先级时,可以使用以下两种方式:

//方式一:以成员函数的形式
#include<queue>
#include<iostream>
using namespace std;
struct Student{
    //简单起见,只定义两个成绩变量
    int num;
    int math;
    Student(int n, int m){
        num = n;
        math = m;
    }
    bool operator< (const Student &s) const { //这里const不能漏,会报错(codeblocks)
        return math < s.math;
    }
};

int main(){
    priority_queue < Student, vector<Student>, less<Student> > q;

    q.push(Student(7,80));
    q.push(Student(6,30));
    q.push(Student(3,45));
    q.push(Student(2,100));
    q.push(Student(5,76));
    q.push(Student(10,34));
    cout << "数学成绩排序为:" ;
    while( !q.empty() ){
        cout<< q.top().math << " ";
        q.pop();
    }
    return 0;
}
//方式二:以结构体形式
#include<queue>
#include<iostream>
using namespace std;

struct Student{
    //简单起见,只定义两个成绩变量
    int num;
    int math;
    Student(int n, int m){
        num = n;
        math = m;
    }
};

struct cmp{
    bool operator ()(const Student s1, const Student s2){
        return s1.math < s2.math;
    }
};

int main(){
    priority_queue < Student, vector<Student>, cmp > q; //这里要用结构体cmp替换原来的less/greater

    q.push(Student(7,80));
    q.push(Student(6,30));
    q.push(Student(3,45));
    q.push(Student(2,100));
    q.push(Student(5,76));
    q.push(Student(10,34));
    cout << "数学成绩排序为:" ;
    while( !q.empty() ){
        cout<< q.top().math << " ";
        q.pop();
    }
    return 0;
}

输出结果均为:

数学成绩排序为:100 80 76 45 34 30

注意

针对方式一,如果在声明中compare选择greater,则在结构体中重载函数名必须对应为operator >,即重载运算符>;同理,less对应operator <,即重载运算符<, 即:

//greater ----- operator>
priority_queue < Student, vector<Student>, greater<Student> > q;
bool operator> (const Student &s) const {}

//less ----- operator<
priority_queue < Student, vector<Student>, less<Student> > q;
bool operator< (const Student &s) const {}

针对方式二,重载运算符必须是(), 即:

bool operator ()(const Student s1, const Student s2) {}

否则会报错。

但是,最终排序结果只与return语句中的运算符有关,即:

//如果你想让元素从大到小出列,则return中运算符应为'<'
return math < s.math;

//如果你想让元素从小到大出列,则return中运算符应为'>'
return math > s.math

小结

以上内容浅入浅出,只是为了OJ刷题需要,没有追根溯源。如有错误,欢迎指正!

  • 2
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值