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

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

常用的Member Functions

function Description Return
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刷题需要,没有追根溯源。如有错误,欢迎指正!

猜你喜欢

转载自blog.csdn.net/disguise666/article/details/85989788