-
最大堆,最小堆
最大堆:每个节点的孩子节点都小于该节点
最小堆:每个节点的孩子节点都大于该节点由于堆是一棵完全二叉树,所以
- 如果堆中的节点
i
有左右孩子节点,则:
左孩子节点:i x 2 + 1
右孩子节点:i x 2 + 2
- 如果堆中的节点
j
有父节点,则:
父节点:(j-1)/2
-
建立最大堆:
- 从最后的非叶子节点开始调整堆,一直到根节点
- 以某个节点为根,调整堆
a. 如果孩子节点大于该节点,将该节点与左右孩子节点中最大的节点交换,然后调整其孩子节点
b. 否则,无需调整
c. 反复这个过程,直至叶子节点或者直至无需调整
void AdjustHeap(std::vector<int> & heap, int cur, int length) { int left = cur * 2 + 1, right = cur * 2 + 2; int large = cur; if (left < length && heap[left] > heap[large]) { large = left; } if (right < length && heap[right] > heap[large]) { large = right; } if (large != cur) { std::swap(heap[large], heap[cur]); AdjustHeap(heap, large, length); } } //从最后的非叶子节点开始调整堆,一直到根节点 void buildHeap(std::vector<int> & data) { for(int i = (data.size() - 1 - 1)>> 1; i >= 0; i--) { AdjustHeap(data, i, data.size()); } }
-
AdjustHeap的非递归方式:
- 使用循环, 找到每个需要调整的孩子节点,直至当前节点找到合适的位置
void AdjustHeap_NotRec(std::vector<int> & heap, int cur, int length) { int large = cur; for (int child = cur * 2 + 1; child < length; child = cur * 2 + 1) { if (heap[child] > heap[large]) { large = child; } child++; if (child < length && heap[child] > heap[large]) { large = child; } if (large != cur) { std::swap(heap[large], heap[cur]); cur = large; } else { break; } } }
-
堆排序:
- 将每个根节点与最后的节点交换,然后调整除开最后一个节点的数据为最大堆
void sortHeap(std::vector<int> & data) { int length = data.size(); for(int i = data.size() - 1; i >= 0; i--) { std::swap(data[i], data[0]); AdjustHeap(data, 0, length - 1); --length; } }
ps:如果寻找第k个最大值,可以将for循环的条件为:i > data.size() - k,并且返回data[0]
-
在堆中加入节点:
- 将节点加入到数据中
- 向上调整节点,将该节点交换到可以到达的最靠近根的地方
void pushHeap(std::vector<int> & data, int num) { data.push_back(num); int cur = data.size() - 1; for (int parent = (cur - 1) >> 1; parent >= 0; parent = parent >> 1) { if (data[cur] > data[parent]) { std::swap(data[cur], data[parent]); cur = parent; } else { break; } } }
-
验证的main:
int main(int argc, char * argv[]) { std::vector<int> data = {3, 2, 3, 1, 2, 4, 5, 5, 6}; buildHeap(data); pushHeap(data, 8); sortHeap(data); for(auto & num : data) { std::cout << num << " "; } std::cout << std::endl; return 0; }
输出:
1 2 2 3 3 4 5 5 6 8
- 如果堆中的节点
-
priority_queue
在c++中,可以通过优先队列
priority_queue
这个类管理最大堆或者最小堆。
其头文件在<queue>
中,定义如下:
priority_queue<T, Container, std::less<T>>
为最大堆
priority_queue<T, Container, std::greater<T>>
为最小堆#include <iostream> #include <queue> #include <vector> template<typename T> void print_queue(T q) { while(!q.empty()) { std::cout << q.top() << " "; q.pop(); } std::cout << std::endl; } int main(int argc, char * argv[]) { const auto data = {3, 2, 3, 1, 2, 4, 5, 5, 6}; std::priority_queue<int, std::vector<int>, std::less<int>> q1; for (auto & num : data) { q1.push(num); } print_queue(q1); // another init way std::priority_queue<int, std::vector<int>, std::less<int>> q2(data.begin(), data.end()); print_queue(q2); // using lambda to compare elements auto cmp = [](int left, int right) {return left < right;}; std::priority_queue<int, std::vector<int>, decltype(cmp)> q3(data.begin(), data.end(), cmp); print_queue(q3); return 0; }
输出为:
6 5 5 4 3 3 2 2 1 6 5 5 4 3 3 2 2 1 6 5 5 4 3 3 2 2 1
https://en.cppreference.com/w/cpp/container/priority_queue
最大堆, 最小堆, priority_queue
最新推荐文章于 2024-04-22 20:24:35 发布