priority_queue稱為“優先隊列”,其底層是用堆實作。
在優先隊列中,隊首元素一定是目前隊列中優先級最高的哪一個。
例如,若在隊列中有如下元素且定義好了優先級:
埃羅芒阿(優先級3)
土間埋(優先級2)
公主殿下(優先級5)
複制
那麼出隊的序列為公主殿下(5)->埃羅芒阿(3)->土間埋(2)。
而且可以在任何時候往優先隊列裡面加入(push)元素,接着優先隊列底層的資料結構堆會随時調整結構,使得每次的隊首元素都是優先級最大的。(這裡的優先級是可以規定出來的,預設是數字越大優先級越大)
使用priority_queue需于代碼頭部添加
#include
,并且随後加上一句:
using namespace std;
即可。
priority_queue的定義
定義:
priority_queue name;
擷取堆頂元素
top():可以獲得隊首元素(堆頂元素),時間複雜度為O(1)。
與隊列不一樣的是,優先隊列通過top()函數來通路隊首元素(堆頂元素)。(隊列是通過front()函數和back()函數通路下标)
入隊
push(x):令x入隊,時間複雜度為O(logN),其中N為目前優先隊列中的元素個數。
出隊
pop():令隊首元素(堆頂元素)出隊,時間複雜度為O(logN),其中N為目前優先隊列中的元素個數。
檢測是否為空
empty():檢測優先隊列是否為空,傳回true為空,false為非空。時間複雜度為O(1)
擷取元素個數
size():用來獲得優先隊列中元素的個數,時間複雜度為O(1)
代碼:
#include
#include
using namespace std;
int main(){
priority_queue q;
//入隊
q.push(3);
q.push(4);
q.push(1);
//通過下标通路元素
printf("%d\n",q.top());//輸出4
//出隊
q.pop();
printf("%d\n",q.top());//輸出3
//檢測隊列是否為空
if(q.empty() == true) {
printf("Empty\n");
} else {
printf("Not Empty\n");
}
//擷取長度
//printf("%d\n",q.size());//輸出3
}
複制
優先隊列内元素優先級的設定
常見用途
需要建立字元或字元串與整數之間映射的題目
判斷大整數或者其他類型資料是否存在的問題,可以把map當成bool數組用
字元串和字元串的映射也有可能會用到
延伸
(1)如果一個鍵需要對應多個值,隻能使用multimap而不能使用map。
(2)C++11标準還增加了unordered_map,以散列替代map内部的紅黑樹實作,使其可以用來處理值隻映射而不按key排序的需求,速度比map快很多。
優先隊列内元素優先級的設定
如何定義優先隊列内元素的優先級是運用好優先隊列的關鍵。
基本資料類型的優先級設定
一般情況下,數字大的優先級更高。(char類型的為字典序最大)
對于基本結構的優先級設定。下面兩種優先隊列的定義是等價的:
priority_queue<int> q;
priority_queue<int, vector<int>, greater<int>> q;
第二種定義方式中的括号裡:
-
第二個參數填寫的是成在底層資料結構堆(heap)的容器;
若第一個參數為double或char,則隻需要填寫
或vector<double>
。vector<char>
- 第三個參數是對一個參數的比較類;
表示數字大的優先級越大,而less<int>
則反之`greater<int>
舉個例子:
如果想讓優先隊列總是把最小的元素放在隊首,需進行以下定義: priority_queue<int, vector<int>, grater<int>> q;
結構體的優先級設定
舉個例子:
下面是關于動漫人物的結構體
struct comic_character{ string name; int bust; };
現在希望按動漫人物胸圍大的為優先級高,就需要使用重載(overload)運算符小于"<"。
而重載是指對已有運算符進行重新定義,即把改變其功能将其重載為大于号的功能。
以下為其寫法:
struct comic_character{
string name;
int bust;
friend bool operator < (comic_character c1, comic_character c2){
return c1.bust < c2.bust;
}
};
複制
其中,結構體中增加了一個函數。
"friend"為友元。
後面一大串是對comic_character類型的操作符“<”進行了重載。此處重載後小于号還是小于号的作用。
提示:重載大于号會編譯錯誤(一般來說隻需要重載小于号,即c1>c2等價于c2<c1,c1==c2等價于判斷 !(c1<c2)&&!(c2<c1)
)
若想要以胸圍小的動漫人物為優先級高,那麼隻需要把return中的小于改為大于号即可,此處不再贅述。
重大發現:重載與sort函數的比較。
這裡對小于号的重載與排序函數sort中cmp函數有點類似。它們的參數和函數内部看似都是一樣的。
雖然這兩者的作用是類似的,但是效果看上去似乎的“相反”的。
在sort中,如果是"return c1.bust > c2.price",那麼則是按胸圍從大到小排序。
而在優先隊列的重載中卻是把胸圍小的放到隊首。
總之《優先隊列的重載與sort中的cmp函數的效果是相反的。
另外
怎麼把重載放在結構體外面(正如sort中的cmp函數)呢?
隻要把friend去掉,把小于号改成一對小括号,然後把重載的函數寫在結構體外面,同時将其struct包裝起來。
即:
struct comic_character{
string name;
int bust;
};
struct cmp{
bool operator () (comic_character c1, comic_character c2){
return c1.bust > c2.bust;
}
};
int main(){
priority_queue<comic_character, vector<comic_character>, cmp> q;
......
}
複制
小提示
(1)即使是基本資料類型或者其他STL容器(如set),也可通過“另外”部分的方式來定義優先級。
(小作業:想想怎麼定義?)
(2)使用top()函數前,必須使用empty()判斷優先隊列是否為空。
題外話
如果結構體内的資料較為龐大(如字元串或數組),建議使用引用來提高效率,在比較類的參數中加上"const"和"&"。
即:
在結構體内:
friend bool operator < (const comic_character &c1, const comic_character &c2){ return c1.bust > c2.bust; }
或
在結構體外:
bool operator () (const comic_character &c1, const comic_character &c2){ return c1.bust > c2.bust; }
常見用途
(1)可以解決一些貪心問題
(2)也可以對Dijkstra算法進行優化
優先隊列的本質是堆
版權所有:可定部落格 © WNAG.COM.CN
本文标題:《C++ STL容器之priority_queue(優先隊列)快速入門》
本文連結:https://wnag.com.cn/816.html
特别聲明:除特别标注,本站文章均為原創,本站文章原則上禁止轉載,如确實要轉載,請電聯:[email protected],尊重他人勞動成果,謝過~