优先队列详解priority_queue .RP
优先队列:顾名思义,首先它是一个队列,但是它强调了“优先”二字,所以,已经不能算是一般意义上的队列了,它的“优先”意指取队首元素时有一定的选择性,即根据元素的属性选择某一项值最优的出队~
百度百科上这样描述的:
优先级队列 是不同于先进先出队列的另一种队列。每次从队列中取出的是具有最高优先权的元素
优先队列的类定义
优先队列是0个或多个元素的集合,每个元素都有一个优先权或值,对优先队列执行的操作有1) 查找;2) 插入一个新元素;3) 删除.在最小优先队列(min priorityq u e u e)中,查找操作用来搜索优先权最小的元素,删除操作用来删除该元素;对于最大优先队列(max priority queue),查找操作用来搜索优先权最大的元素,删除操作用来删除该元素.优先权队列中的元素可以有相同的优先权,查找与删除操作可根据任意优先权进行.
优先队列,其构造及具体实现可以先不用深究,现在只需要了解其特性,及在做题中的用法,看过之后会收获不少。
使用优先队列,首先要包函STL头文件 #include <queue>
以一个例子来解释吧(呃,写完才发现,这个代码包函了几乎所有我们要用到的用法,仔细看看吧):
- /*优先队列的基本使用 2010/7/24 dooder*/
- #include<stdio.h>
- #include<functional>
- #include<queue>
- #include<vector>
- using namespace std;
- //定义结构,使用运算符重载,自定义优先级1
- struct cmp1{
- bool operator ()(int &a,int &b){
- return a>b;//最小值优先
- }
- };
- struct cmp2{
- bool operator ()(int &a,int &b){
- return a<b;//最大值优先
- }
- };
- //定义结构,使用运算符重载,自定义优先级2
- struct number1{
- int x;
- bool operator < (const number1 &a) const {
- return x>a.x;//最小值优先
- }
- };
- struct number2{
- int x;
- bool operator < (const number2 &a) const {
- return x<a.x;//最大值优先
- }
- };
- int a[]={,,,,,,,,,,,};
- number1 num1[]={,,,,,,,,,,,};
- number2 num2[]={,,,,,,,,,,,};
- int main()
- { priority_queue<int>que;//采用默认优先级构造队列
- priority_queue<int,vector<int>,cmp1>que1;//最小值优先
- priority_queue<int,vector<int>,cmp2>que2;//最大值优先
- priority_queue<int,vector<int>,greater<int> >que3;//注意“>>”会被认为错误,
- //这是右移运算符,所以这里用空格号隔开
- priority_queue<int,vector<int>,less<int> >que4;////最大值优先
- priority_queue<number1>que5;
- priority_queue<number2>que6;
- int i;
- for(i=;a[i];i++){
- que.push(a[i]);
- que1.push(a[i]);
- que2.push(a[i]);
- que3.push(a[i]);
- que4.push(a[i]);
- }
- for(i=;num1[i].x;i++)
- que5.push(num1[i]);
- for(i=;num2[i].x;i++)
- que6.push(num2[i]);
- printf("采用默认优先关系:\n(priority_queue<int>que;)\n");
- printf("Queue 0:\n");
- while(!que.empty()){
- printf("%3d",que.top());
- que.pop();
- }
- puts("");
- puts("");
- printf("采用结构体自定义优先级方式一:\n(priority_queue<int,vector<int>,cmp>que;)\n");
- printf("Queue 1:\n");
- while(!que1.empty()){
- printf("%3d",que1.top());
- que1.pop();
- }
- puts("");
- printf("Queue 2:\n");
- while(!que2.empty()){
- printf("%3d",que2.top());
- que2.pop();
- }
- puts("");
- puts("");
- printf("采用头文件\"functional\"内定义优先级:\n(priority_queue<int,vector<int>,greater<int>/less<int> >que;)\n");
- printf("Queue 3:\n");
- while(!que3.empty()){
- printf("%3d",que3.top());
- que3.pop();
- }
- puts("");
- printf("Queue 4:\n");
- while(!que4.empty()){
- printf("%3d",que4.top());
- que4.pop();
- }
- puts("");
- puts("");
- printf("采用结构体自定义优先级方式二:\n(priority_queue<number>que)\n");
- printf("Queue 5:\n");
- while(!que5.empty()){
- printf("%3d",que5.top());
- que5.pop();
- }
- puts("");
- printf("Queue 6:\n");
- while(!que6.empty()){
- printf("%3d",que6.top());
- que6.pop();
- }
- puts("");
- return ;
- }
- /*
- 运行结果 :
- 采用默认优先关系:
- (priority_queue<int>que;)
- Queue 0:
- 91 83 72 56 47 36 22 14 10 7 3
- 采用结构体自定义优先级方式一:
- (priority_queue<int,vector<int>,cmp>que;)
- Queue 1:
- 3 7 10 14 22 36 47 56 72 83 91
- Queue 2:
- 91 83 72 56 47 36 22 14 10 7 3
- 采用头文件"functional"内定义优先级:
- (priority_queue<int,vector<int>,greater<int>/less<int> >que;)
- Queue 3:
- 3 7 10 14 22 36 47 56 72 83 91
- Queue 4:
- 91 83 72 56 47 36 22 14 10 7 3
- 采用结构体自定义优先级方式二:
- (priority_queue<number>que)
- Queue 5:
- 3 7 10 14 22 36 47 56 72 83 91
- Queue 6:
- 91 83 72 56 47 36 22 14 10 7 3
- */
好了,如果你仔细看完了上面的代码,那么你就可以基本使用优先队列了,下面给出一些我做题中有过的一些应用,希望能给大家带来一些启
示~
下面给出本文出处:http://www.cnblogs.com/heqinghui/archive/2013/07/30/3225407.html
附原作者部分代码↓↓↓
1、先来一个我们最近做的题吧,http://acm.hdu.edu.cn/showproblem.php?pid=1242
题意:某人被关在囚笼里等待朋友解救,问能否解救成功,最少需要多少时间~
具体:可同时有几个朋友,每走一格消耗一分钟的时间 ,地图上还存在着卫兵,卫兵可以解决掉,但是要另外花费一分钟~
分析:从“a”出发,此题可以用回溯法进行深搜,但那样做的话,效率还是不能让人满意,但是广搜的话,由于入队后每次出队时,根据地
图情况的不同,出队元素所记忆的时间并不是层次递增的,因此使用简单广搜的话,同样需要全部搜索才能找到正确答案。有没有一种方法能
让某一步因为遇到士兵而多花时间的结点在队列中向后推迟一层出队呢?答案是肯定的,在这里我们可以用优先队列来实现,总体思想上是,
根据时间进行优先性选择,每次都要出队当前队列元素中记录时间最少的出队,而入队处理时,我们可以按顺序对四个方向上的各种情况按正
常处理入队就行了,出队顺序由优先队列根据预设优先性自动控制。这样,我们就可以从“a”进行基于优先队列的范围搜索了,并且在第一
次抵达有朋友的位置时得到正确结果~具体实现代码:
- /*HDU 1242 基于优先队列的范围搜索,16ms dooder*/
- #include<stdio.h>
- #include<queue>
- using namespace std;
- #define M 201
- typedef struct p{
- int x,y,t;
- bool operator < (const p &a)const
- {
- return t>a.t;//取时间最少优先
- }
- }Point;
- char map[M][M];
- Point start;
- int n,m;
- int dir[][]={{,},{-,},{,},{,-}};
- int bfs()
- {
- priority_queue<Point>que;
- Point cur,next;
- int i;
- map[start.x][start.y]='#';
- que.push(start);
- while(!que.empty()){
- cur=que.top();//由优先队列自动完成出队时间最少的元素
- que.pop();
- for(i=;i<;i++){
- next.x=cur.x+dir[i][];
- next.y=cur.y+dir[i][];
- next.t=cur.t+;
- if(next.x<||next.x>=n||next.y<||next.y>=m)
- continue;
- if(map[next.x][next.y]=='#')
- continue;
- if(map[next.x][next.y]=='r')
- return next.t;
- if(map[next.x][next.y]=='.'){
- map[next.x][next.y]='#';
- que.push(next);
- }
- else if(map[next.x][next.y]=='x'){
- map[next.x][next.y]='#';
- next.t++;
- que.push(next);
- }
- }
- }
- return -;
- }
- int main()
- {
- int i,ans;
- char *p;
- while(scanf("%d%d",&n,&m)!=-){
- for(i=;i<n;i++){
- scanf("%s",map[i]);
- if(p=strchr(map[i],'a')){
- start.x=i;
- start.y=p-map[i];
- start.t=;
- }
- }
- ans=bfs();
- printf(ans+?"%d\n":"Poor ANGEL has to stay in the prison all his life.\n",ans);
- }
- return ;
- }
2、http://acm.hdu.edu.cn/showproblem.php?pid=1053
题意:给出一行字符串,求出其原编码需要的编码长度和哈夫曼编码所需的长度,并求其比值
分析:根据哈夫曼生成树的生成过程可知,其生成树的权值是固定的而且这个值是最小的,而且其值根据生成树的顺序,我们可以找出规律而
不需要真的去生成一棵树然后再求出权值,其模拟过程为取出队列中权值最小的两个元素,将其值加入结果中,然后将这两个元素的权值求和
即得出其父节点的权值,将生成元素作为结点入队~~如此循环,直至取出队列中最后两个元素加入结果,实现代码如下:
- /*HDU 1053 采用广搜求哈夫曼生成树的权值 0ms dooder*/
- #include<stdio.h>
- #include<string.h>
- #include<ctype.h>
- #include<functional>
- #include<queue>
- using namespace std;
- #define M 1000050
- char str[M];
- int list[];
- priority_queue< int,vector<int>,greater<int> >que;
- int main()
- {
- int ans,sum;
- int i,a,b,c;
- while(scanf("%s",str),strcmp(str,"END")){
- memset(list,,sizeof(list));
- for(i=;str[i];i++){
- if(isalpha(str[i]))
- list[str[i]-'A']++;
- else
- list[]++;
- }
- sum=i*;ans=i;c=;
- for(i=;i<;i++){
- if(list[i]){
- que.push(list[i]);
- c++;
- }
- }
- if(c>){ans=;//注意只有一种字符的情况
- while(que.size()!=){
- a=que.top();
- que.pop();
- b=que.top();
- que.pop();
- ans+=a+b;
- que.push(a+b);
- }
- while(!que.empty())//使用后清空队列
- que.pop();
- }
- printf("%d %d %.1f\n",sum,ans,1.0*sum/ans);
- }
- return ;
- }
3、http://acm.pku.edu.cn/JudgeOnline/problem?id=2263
这是第二次练习赛时,我们做过的最后一题,这里采用优先队列进行实现,在《谁说不能这样做题》中已提到这种方法,在这里再次放出代
码,~
题意:给出各城市间道路的限制载重量,求出从一个城市到另外一个城市的贷车能够运载的最大货物重量。
分析:采用优先队列,每次取出当前队列中结点的minheavy最大值出队,对它的连接结点搜索入队,这样,从出发点开始就可以
在到达终点时求出结果,即最大载货物重,实现代码如下:
- /*POJ 2263 16ms dooder*/
- #include<stdio.h>
- #include<string.h>
- #include<queue>
- using namespace std;
- #define M 201
- typedef struct w{
- int city;
- int mintons;
- bool operator < (const w &a)const {
- return mintons < a.mintons;
- }//优先性定义
- }Way;
- char citys[M][];
- int map[M][M];
- bool mark[M][M];
- int n,m,from,to,ans,k;
- priority_queue <Way> que;
- int min(int a,int b)
- {
- return a>b?b:a;
- }
- void bfs()
- {
- Way cur,next;
- int i;
- while(!que.empty()){
- cur=que.top();
- que.pop();
- if(cur.city==to){
- if(cur.mintons>ans)
- ans=cur.mintons;
- while(!que.empty())
- que.pop();
- return ;
- }
- for(i=;i<n;i++){
- if(map[cur.city][i]&&!mark[cur.city][i]){
- next.city=i;
- next.mintons=min(cur.mintons,map[cur.city][i]);
- mark[cur.city][i]=mark[i][cur.city]=;
- que.push(next);
- }
- }
- }
- }
- void run()
- {
- int i,temp,index;
- Way cur;
- ans=;
- memset(mark,,sizeof(mark));
- temp=;
- for(i=;i<n;i++){
- if(map[from][i]>temp){
- temp=map[from][i];
- index=i;
- }
- }
- cur.city=index;
- cur.mintons=temp;
- que.push(cur);
- bfs();
- }
- int main()
- {
- int k1,k2,tons,t=;
- char s1[],s2[];
- while(scanf("%d%d",&n,&m),n||m){
- k=;
- while(m--){
- scanf("%s%s%d",s1,s2,&tons);
- for(k1=;strcmp(s1,citys[k1])&&k1<k;k1++);
- if(k1==k)
- strcpy(citys[k++],s1);
- for(k2=;strcmp(s2,citys[k2])&&k2<k;k2++);
- if(k2==k)
- strcpy(citys[k++],s2);
- map[k1][k2]=map[k2][k1]=tons;
- }
- scanf("%s%s",s1,s2);
- for(from=;strcmp(citys[from],s1);from++);
- for(to=;strcmp(citys[to],s2);to++);
- run();
- printf("Scenario #%d\n",t++);
- printf("%d tons\n\n",ans);
- }
- return ;
- }
当然了,优先队列的用法决不是仅仅提到的这些,各种应用还需要大家去发现,给道题大家可以练习一下hdu 2066\
相信大家已经学到不少了,还有一点可以告诉大家,优先队列是启发式搜索的数据结构基础,希望好好理解,并逐步掌握其用法~
加:失策啊,竟然忘了说优先队列的效率了,其时间复杂度为O(logn).n为队列中元素的个数,存取都需要消耗时间~
优先队列详解priority_queue .RP的更多相关文章
- 如约而至,Java 10 正式发布! Spring+SpringMVC+MyBatis+easyUI整合进阶篇(十四)Redis缓存正确的使用姿势 努力的孩子运气不会太差,跌宕的人生定当更加精彩 优先队列详解(转载)
如约而至,Java 10 正式发布! 3 月 20 日,Oracle 宣布 Java 10 正式发布. 官方已提供下载:http://www.oracle.com/technetwork/java ...
- c++ STL - priority_queue优先队列详解
简述 普通的队列是一种先进先出的数据结构,元素在队列尾追加,而从队列头删除.在优先队列中,元素被赋予优先级.当访问元素时,具有最高优先级的元素最先删除.优先队列具有最高级先出 (first in, l ...
- C++ STL 优先队列详解
一.解释: 优先队列是队列的一种,不过它可以按照自定义的一种方式(数据的优先级)来对队列中的数据进行动态的排序,每次的push和pop操作,队列都会动态的调整,以达到我们预期的方式来存储. 例如,将元 ...
- STL 优先队列详解
优先队列是一个保证队列里元素单调的队列,我们可以利用它来维护一个线性结构的单调性. 一般的优先队列: 当然需要加头文件 #include <queue> priority_queue &l ...
- C++优先队列详解
转自csdn的文章,仅作为学习笔记.原文链接:https://blog.csdn.net/weixin_36888577/article/details/79937886 普通的队列是一种先进先出的数 ...
- 【Java基础】JAVA中优先队列详解
总体介绍 优先队列的作用是能保证每次取出的元素都是队列中权值最小的(Java的优先队列每次取最小元素,C++的优先队列每次取最大元素).这里牵涉到了大小关系,元素大小的评判可以通过元素本身的自然顺序( ...
- STL priority_queue 常见用法详解
<算法笔记>学习笔记 priority_queue 常见用法详解 //priority_queue又称优先队列,其底层时用堆来实现的. //在优先队列中,队首元素一定是当前队列中优先级最高 ...
- 【STL】优先队列priority_queue详解+OpenJudge-4980拯救行动
一.关于优先队列 队列(queue)这种东西广大OIer应该都不陌生,或者说,队列都不会你还学个卵啊(╯‵□′)╯︵┻━┻咳咳,通俗讲,队列是一种只允许从前端(队头)删除元素.从后端(队尾)插入元素的 ...
- 详解C++ STL priority_queue 容器
详解C++ STL priority_queue 容器 本篇随笔简单介绍一下\(C++STL\)中\(priority_queue\)容器的使用方法和常见的使用技巧. priority_queue容器 ...
随机推荐
- Unity3D教程:制作与载入AssetBundle
通常我们在游戏程式执行过程,并不希望一次将全部的资源都载入,而比较希望实际上有使用到的才载入,以免占用多余的记忆体,所以我们可能会尽量规划好不同功能的场景,在需要时才载入场景并释放掉前个场景中不需要的 ...
- 1110. Complete Binary Tree (25)
Given a tree, you are supposed to tell if it is a complete binary tree. Input Specification: Each in ...
- [BZOJ1242]Fishing Net
dbzoj vjudge1 vjudge2 sol 给一个无向图,求判定是不是弦图. sol 还是弦图那套理论. 复杂度是\(O(n^2)\)的,因为\(m\)本质上和\(n^2\)是同级的. cod ...
- LeetCode 369. Plus One Linked List
原题链接在这里:https://leetcode.com/problems/plus-one-linked-list/ 题目: Given a non-negative number represen ...
- C# 读xml注释或过滤xml注释
有这么个需求: 要统计所有的配置文件,这些配置文件都xml格式,并把这些配置写到数据表里,如果有注释要把这些注释写到对应配置对象的描述字段上 <item id="" key= ...
- 市场上 MLCC 226 电容现象
市场上 MLCC 226 电容现象 三星 X7R 1206 没有 16V 也有人在卖. Y5V 当 X7R 卖. X5R 当 X7R 卖. 薄电容当厚的电容卖.
- ipad与iphone的屏幕分辨率
1.ipad分辨率,iphone 6 iPhone设备 尺寸 分辨率 点iPhone 3和3s 3.5英寸 (320×480) 3 ...
- grafana 4.0.2 + openfalcon query 1.4.3
转:http://blog.csdn.net/vbaspdelphi/article/details/53884282 grafana 4.0.2 加上官方app自带的openfalcon插件, 可以 ...
- NB-LOT 科普
最全科普!你一定要了解的NB-IoT 2017-06-19 21:04物联网/操作系统/科普 工信部下发通知推动150万NB-IoT基站落地.NB-IoT汹涌而来.很多网友要求雇佣军科普一篇NB-Io ...
- java代码swing编程JPaswordField类
总结:JPasswordField类是JTextField类的子类.用户在JPasswordField对象中输入的字符会被其他的字符替代 而挡住,JPasswordFiled组件主要用来输入口令 pa ...