STL實現
C++中,大根堆和小根堆可以使用優先隊列實現。
#include <queue>
priority_queue<int> pq1 // 大根堆
priority_queue<int, vector<int>, greater<int>> pq2 // 小根堆
該STL支持自定義比較函數,但與sort不同,不支持直接使用lambda函數。自定義的小根堆如下。
struct cmp {bool operator()(int a,int b) {return a > b;}}; // 自定義小根堆
priority_queue<int, vector<int>, cmp> pq;
更加復雜的自定義函數可以參照【LeetCode-1792】最大平均通過率。
手寫
大小根堆的前備知識為堆排序,具體是使用堆排序中的節點上浮(swim)和下沉(sink)實現。整體的數據結構可以使用vector
。push
新的數值時,將其放在數組最后,然后與對應位置的父節點比較,進行上浮操作;pop
堆頂數值時,將該節點與隊尾數字交換,然后移除隊尾數字,並對當前交換后的堆頂元素進行下沉操作。具體代碼如下。
vector<int> pq{0}; // 首位填充一個數值,方便找根節點與子節點
void insert(int num) {
pq.push_back(num);
swim(pq.size() - 1);
}
int popTop() {
swap(pq[1], pq.back());
int res = pq.back();
pq.pop_back();
sink(1);
return res;
}
int peekTop() {
return pq[1];
}
bool isPrior(int i, int j) { // 自定義函數部分,此處實現的是大根堆
return pq[i] > pq[j];
}
void swim(int i) { // 子節點與父節點比較
while (i > 1 && isPrior(i, i / 2)) {
swap(pq[i], pq[i / 2]);
i /= 2;
}
}
void sink(int i) { // 父節點與左右節點中最大的進行比較
int n = pq.size();
while (i * 2 < n) {
int j = i * 2;
if (j + 1 < n && isPrior(j + 1, j)) j++;
if (isPrior(i , j)) break;
swap(pq[i], pq[j]);
i = j;
}
}