STL priority_queue 常見用法詳解


《算法筆記》學習筆記

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算法進行優化(因為優先隊列的本質是堆)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM