0.定义
大顶堆 :树中所有根节点必须大于等于其左儿子和右儿子,因此根节点是最大值。
小顶堆:树中所有根节点必须大于等于其左儿子和右儿子,因此根节点是最小值。
1.自己实现大顶堆和小顶堆
cpp
#pragma once
#include <vector>
#include <iostream>
#include <assert.h>
using namespace std;
// 小顶堆
template <class T>
struct myGreater
{
bool operator()(const T &left, const T &right) { return left > right; }
};
// 大顶堆
template <class T>
struct myLess
{
bool operator()(const T &left, const T &right) { return left < right; }
};
template <class T, class Compare = myLess<T>>
class myHeap
{
public:
myHeap() {}
myHeap(vector<T> vec)
{
_array.reserve(vec.size());
_array.assign(vec.begin(), vec.end());
// 建堆
for (int i = _array.size() / 2 - 1; i >= 0; i--)
AjustDown(i);
}
bool empty() const { return _array.empty(); }
size_t size() const { return _array.size(); }
T &top()
{
assert(!_array.empty());
return _array[0];
}
void push(T elem)
{
_array.push_back(elem);
AjustUp(_array.size() - 1);
}
void pop()
{
assert(!_array.empty());
swap(_array[0], _array[_array.size() - 1]);
_array.pop_back();
AjustDown(0);
}
private:
void AjustDown(int parent)
{
int child = parent * 2 + 1; // left child idx
while (child < _array.size())
{
if (child + 1 < _array.size() && cmp(_array[child], _array[child + 1]))
++child;
if (cmp(_array[parent], _array[child]))
{
swap(_array[parent], _array[child]);
parent = child;
child = 2 * parent + 1;
}
else
break;
}
}
void AjustUp(int child)
{
int parent = (child - 1) / 2;
while (parent >= 0)
{
if (cmp(_array[parent], _array[child]))
{
swap(_array[parent], _array[child]);
child = parent;
parent = (child - 1) / 2;
}
else
break;
}
}
vector<T> _array;
Compare cmp;
};
template <typename T>
using maxHeap = myHeap<T,myLess<T>>;
template <typename T>
using minHeap = myHeap<T,myGreater<T>>;
int main()
{
vector<int> a = {11, 10, 13, 12, 16, 18, 15, 17, 14, 19};
myHeap<int> hp1(a);
cout << hp1.top() << endl;
hp1.push(90);
hp1.push(900);
cout << hp1.top() << endl;
hp1.pop();
hp1.pop();
hp1.pop();
hp1.pop();
hp1.pop();
hp1.pop();
hp1.pop();
// system("pause");
return 0;
}
比较重要的是:
- 仿函数的写法:大顶堆是left<right,命名为Less;小顶堆是left>right,命名为Greater。
- 堆调整是
cmp(_array[parent], _array[child])
或者cmp(_array[left_child], _array[right_child])
,这个顺序是和第一步仿函数的写法对应。这个过程详细描述如下:(以Less为例),Less是left<right写法,
第一步,进行左孩子取值 < 右孩子取值
比较,如果为真,使用右孩子与父节点比较,否则使用做孩子与父节点比较(见AjustDown
函数体内while
循环后第一个if
语句);
第二步,在父节点取值 < 孩子节点取值
时,交换父和子,于是取值较大的孩子节点成为根节点(也就是说这个堆是大顶堆)。
2.STL优先队列
给自己打个广告:找工作准备刷题day1 栈与队列
优先队列练手:Leetcode347.前K个高频元素
自己写完以后更好地理解 为什么 小顶堆
的仿函数 是 >