数据结构 之 priority_queue(优先级队列)
优先级队列,也简称优先队列,比较常用的一种数据结构。这里主要说一下用C++ STL中的priority_queue 实现。
priority_queue的概念:
如果我们给每个元素都分配一个数字来标记其优先级,不妨设较小的数字具有较高的优先级,这样我们就可以在一个集合中访问优先级最高的元素并对其进行查找和删除操作了。这样,我们就引入了优先级队列 这种数据结构。 优先级队列(priority queue) 是0个或多个元素的集合,每个元素都有一个优先权,对优先级队列执行的操作有(1)查找(2)插入一个新元素 (3)删除 一般情况下,查找操作用来搜索优先权最大的元素,删除操作用来删除该元素 。对于优先权相同的元素,可按先进先出次序处理或按任意优先权进行。
优先队列作为一个容器适配器,它使用其它容器作为底层容器,并提供一系列访问元素的函数。优先队列中的元素从底层容器的“尾部(back)”弹出,即是从队列的顶部(top)弹出。底层容器需要满足的条件是可以通过迭代器随机访问其中的元素并且支持以下的操作:
#include <iostream>
#include <queue>
using namespace std;
int main(){
priority_queue<int> q;
int a[5]={1,5,3,2,4};
for( int i= 0; i< 5; ++i ) q.push( a );
while( !q.empty() ){
cout << q.top() << " ";
q.pop();
}
cout << endl;
return 0;
}
// 输出结果:5 4 3 2 1
如果要用到小顶堆,则一般要把模板的三个参数都带进去。
priority_queue的概念:
如果我们给每个元素都分配一个数字来标记其优先级,不妨设较小的数字具有较高的优先级,这样我们就可以在一个集合中访问优先级最高的元素并对其进行查找和删除操作了。这样,我们就引入了优先级队列 这种数据结构。 优先级队列(priority queue) 是0个或多个元素的集合,每个元素都有一个优先权,对优先级队列执行的操作有(1)查找(2)插入一个新元素 (3)删除 一般情况下,查找操作用来搜索优先权最大的元素,删除操作用来删除该元素 。对于优先权相同的元素,可按先进先出次序处理或按任意优先权进行。
优先队列作为一个容器适配器,它使用其它容器作为底层容器,并提供一系列访问元素的函数。优先队列中的元素从底层容器的“尾部(back)”弹出,即是从队列的顶部(top)弹出。底层容器需要满足的条件是可以通过迭代器随机访问其中的元素并且支持以下的操作:
- front()
- push_back()
- pop_back()
故此,容器vector和deque可以作为底层容器,在创建优先队列时若没有声明使用何种容器,则默认使用vector。
priority_queue的创建:
priority_queue 对于基本类型的使用方法相对简单。他的模板声明带有三个参数:
priority_queue<Type, Container, Functional>
其中Type 为数据类型, Container 为保存数据的容器,Functional 为元素比较方式。
Container 必须是用数组实现的容器,比如 vector, deque 但不能用 list.
STL里面默认用的是 vector. 比较方式默认用 operator< , 所以如果你把后面俩个参数缺省的话,优先队列就是大顶堆,队头元素最大。
下面是最简单的一种用法:priority_queue<Type, Container, Functional>
其中Type 为数据类型, Container 为保存数据的容器,Functional 为元素比较方式。
Container 必须是用数组实现的容器,比如 vector, deque 但不能用 list.
STL里面默认用的是 vector. 比较方式默认用 operator< , 所以如果你把后面俩个参数缺省的话,优先队列就是大顶堆,队头元素最大。
#include <iostream>
// 输出结果:5 4 3 2 1
如果要用到小顶堆,则一般要把模板的三个参数都带进去。
STL里面定义了一个仿函数 greater<>,对于基本类型可以用这个仿函数声明小顶堆
例如:
// 输出结果:1 2 3 4 5
自定义类型重载 operator< 后,声明对象时就可以只带一个模板参数。
例如:
#include <iostream>
#include <queue>
using namespace std;
int main(){
priority_queue<int, vector<int>, greater<int> > q;
int a[5]={1,5,3,2,4};
for( int i= 0; i< 5; ++i ) q.push( a );
while( !q.empty() ){
cout << q.top() << " ";
q.pop();
}
cout << endl;
return 0;
}
// 输出结果:1 2 3 4 5
对于自定义类型,则必须自己重载 operator< 或者自己写仿函数
例如:
例如:
#include <iostream>
#include <queue>
#include<cstdlib>
using namespace std;
struct Node{
int x, y;
Node( int a= 0, int b= 0 ):
x(a), y(b) {}
};
bool operator<( Node a, Node b ){
if( a.x== b.x ) return a.y> b.y;
return a.x> b.x;
}
int main(){
priority_queue<Node> q;
for( int i= 0; i< 10; ++i )
q.push( Node( rand(), rand() ) );
while( !q.empty() ){
cout << q.top().x << ' ' << q.top().y << endl;
q.pop();
}
return 0;
} 自定义类型重载 operator< 后,声明对象时就可以只带一个模板参数。
但此时不能像基本类型这样声明
priority_queue<Node, vector<Node>, greater<Node> >;
原因是 greater<Node> 没有定义,如果想用这种方法定义则可以按如下方式:
}
priority_queue的成员函数:
priority_queue<Node, vector<Node>, greater<Node> >;
原因是 greater<Node> 没有定义,如果想用这种方法定义则可以按如下方式:
#include <iostream>
#include <queue>
using
namespace
std;
struct
Node{
int
x, y;
Node(
int
a= 0,
int
b= 0 ):
x(a), y(b) {}
};
struct
cmp{
bool
operator() ( Node a, Node b ){
if
( a.x== b.x )
return
a.y> b.y;
return
a.x> b.x; }
};
int
main(){
priority_queue<Node, vector<Node>, cmp> q;
for
(
int
i= 0; i< 10; ++i )
q.push( Node(
rand
(),
rand
() ) );
while
( !q.empty() ){
cout << q.top().x <<
' '
<< q.top().y << endl;
q.pop();
}
getchar
();
return
0;
priority_queue的成员函数:
(1)priority_queue::empty
判断队列是否为空(也即是size是否为0),是则返回true,否则返回false。优先队列的此成员函数实际上调用底层容器的同名函数。
(2)priority_queue::size
返回队列中元素的个数。此函数实际上调用底层容器的同名函数。这个函数也可以用于判断队列是否为空。
(3)priority_queue::top
返回队头元素的常引用,队头元素是在所设定的比较关系下最大也即优先级最高的元素。此函数实际上调用底层容器的front函数。
(4)priority_queue::pop
清除队头元素。
(5)priority_queue::push
给队列插入元素,新元素会按其优先级被排列到适当位置。