《算法筆記》學習筆記
priority_queue 常見用法詳解
//priority_queue又稱優先隊列,其底層時用堆來實現的。
//在優先隊列中,隊首元素一定是當前隊列中優先級最高的那一個。
桃子(優先級 3)
梨子(優先級 4)
蘋果(優先級 1)
//那么出隊順序是:梨子(4) -> 桃子(3) -> 蘋果(1)
//可以在任何時候往優先隊列里面加入(push)元素,而優先隊列底層的數據結構對(heap)
//會隨時調整結構,使得每次的隊首元素都是優先級最大的
1. priority_queue 的定義
//定義
priority_queue< typename > name;
2. priority_queue容器內元素訪問
//只能通過top()函數來訪問隊首元素(也稱堆頂元素),也就是優先級最高的元素
#include <stdio.h>
#include <queue>
using namespace std;
int main() {
priority_queue<int> q;
q.push(3);
q.push(4);
q.push(1);
printf("%d\n", q.top());
return 0;
}
3. priority_queue常用函數實例解析
(1) push()
//push(x)將令x入隊,時間復雜度為O(logN),其中N為當前優先隊列中的元素個數。
(2) top()
//top()可以獲得隊首元素,時間復雜度為O(1)
//使用top()函數之前,必須用empty()判斷優先隊列是否為空
(3) pop()
//pop()令隊首元素出隊,時間復雜度為O(logN),其中N為當前優先隊列中的元素個數
#include <stdio.h>
#include <queue>
using namespace std;
int main() {
priority_queue<int> q;
q.push(3);
q.push(4);
q.push(5);
q.push(1);
printf("%d\n", q.top());
q.pop();
printf("%d\n", q.top());
return 0;
}
(4) empty()
//empty()檢測優先隊列是否為空,返回true則空,返回false則非空。時間復雜度為O(1)
#include <stdio.h>
#include <queue>
using namespace std;
int main() {
priority_queue<int> q;
if(q.empty() == true) { //一開始優先隊列內沒有元素,所以是空
printf("Empty\n");
} else {
printf("Not Empty\n");
}
q.push(1);
if(q.empty() == true) { //在加入"1"后,優先隊列非空
printf("Empty\n");
} else {
printf("Not Empty\n");
}
return 0;
}
(5) size()
//size()返回優先隊列內元素的個數,時間復雜度為O(1)
#include <stdio.h>
#include <queue>
using namespace std;
int main() {
priority_queue std;
q.push(3);
q.push(4);
q.push(1);
printf("%d\n", q.size()); //優先隊列中有三個元素
return 0;
}
4.priority_queue內元素優先級的設置
(1) 基本數據類型的優先級設置
//基本數據類型就是int型, double型, char型等可以直接使用的數據類型
//優先隊列對他們的優先級設置一般是數字大的優先級越高
//因此隊首元素就是優先隊列內元素最大的那個(如果是char型,則是字典序最大的)
//下面兩種優先隊列的定義是等價的(以int型為例,注意最后兩個>之間有一個空格):
priority_queue<int> q;
priority_queue<int, vector<int>, less<int>> q;
//第二種定義方式的尖括號內多出兩個參數:vector<int>, less<int>
//其中vector<int>填寫的是來承載底層數據結構堆(heap)的容器
//如果第一個參數是double型或char型,則此處只需要填寫vector<double>或vector<char
//第三個參數less<int>則是對第一個參數的比較類。
//less<int>表示數字大的優先級越大,而greater<int>表示數字小優先級越大
//優先隊列總數把最小的元素放在隊首,定義
priority_queue<int, vector<int>, greater<int>>q;
//示例
#include <stdio.h>
#include <queue>
using namespace std;
int main() {
priority_queue<int, vector<int>, greater<int>> q;
q.push(3);
q.push(4);
q.push(1);
printf("%d\n", q.top());
return 0;
}
(2) 結構體的優先級設置
//對水果的名稱和價格建立結構體
struct fruit {
string name;
int price;
};
//現在希望水果的價格高的為優先級高,就需要重載(overload)小於"<"。
//重載是指對已有的運算符進行重新定義,也就是說,可以改變小於號的功能。
struct fruit {
string name;
int price;
friend bool oprator < (fruit f1, fruit f2) {
return f1.price < f2.price;
}
};
//fruit結構體種增加了一個函數,其中"friend"為友元。
//想要以價格低的水果為優先級高,只需要把return中的小於號改為大於號即可。
struct fruit {
string name;
int price;
friend bool operator < (fruit f1, fruit f2) {
return f1.price > f2.price;
}
};
//示例:
#include <iostream>
#include <string>
#include <queuen>
using namespace std;
struct fruit {
string name;
int price;
friend bool operator < (fruit f1, fruit f2) {
return f1.price > f2.price;
}
}f1, f2, f3;
int main() {
priority_queue<fruit> q;
f1.name = "桃子";
f1.price = 3;
f2.name = "梨子";
f2.price = 4;
f3.name = "蘋果";
f3.price = 1;
q.push(f1);
q.push(f2);
q.push(f3);
cout << q.top().name << " " << q.top().price << endl;
return 0;
}
//優先隊列的這個函數與sort中的cmp函數的效果是相反的
//上面的函數有沒有辦法同sort中的cmp函數那樣卸載結構體外面
//方法:把friend去掉,把小於號改成一對小括號,然后把重載的函數寫在結構體外面
//同時將其用struct包裝起來
struct cmp {
bool operator () (fruit f1,fruit f2) {
return f1.price > f2.price;
}
}
//這種情況需要使用第二種定義方法來定義優先隊列
priority_queue<fruit, vector<fruit>, cmp> q;
//把greater<>部分換成cmp
#include <iostream>
#include <string>
#include <queue>
using namespace std;
struct fruit {
string name;
int price;
} f1, f2, f3;
struct cmp {
bool operator () (fruit f1, fruit f2) {
return f1.price > f2.price;
}
};
int main() {
prority_queue<fruit, vector<fruit>, cmp> q;
f1.name = "桃子";
f1.price = 3;
f2.name = "梨子";
f2.price = 4;
f3.name = "蘋果";
f3.price = 1;
q.push(f1);
q.push(f2);
q.push(f3);
cout << q.top().name << " " << q.top().price << endl;
return 0;
}
//即使是基本數據類型或者其他STL容器(例如set),也可以通過同樣的方式來定義優先級
//建議使用引用來提高效率,在比較類的參數種需要加上"const" 和"&"
friend bool operator < (const fruit &f1, const fruit &f2) {
return f1.price > f2.price;
}
bool operator () (const fruit &f1, const fruit &f2) {
return f1.price > f2.price;
}
5. priority_queueu的常見用途
- 可以解決一些貪心問題
- 也可以對Dijkstra算法進行優化(因為優先隊列的本質是堆)