堆是一个用数组表示的完全二叉树,并满足以下两个特性:
1)父节点的键值总是大于或等于(小于等于)其子树上的任意结点
2)每个结点的左子树和右子树都是个堆。
如果父节点的键值总是大于等于任何一个子节点的键值,那么这时称之为最大堆或者大顶堆。
如果父节点的键值总是小于等于任何一个子节点的键值,那么这时称之为最小堆或者小顶堆。
#pragma once
#include<iostream>
#include<assert.h>
#include<vector>
using namespace std;
//用仿函数将大小堆都实现
template<class T>
struct Less
{
bool operator()(const T& left,const T& right)const
{
return left < right;
}
};
template<class T>
struct Greater
{
bool operator()(const T& left, const T& right) const
{
return left > right;
}
};
//大堆
template<class T, class Compare = Greater<T>>
class Heap // MinHeap
{
public:
Heap()
{}
Heap(T*a, size_t n)
{
_a.reserve(n);
for(size_t i = 0; i < n; ++i)
{
_a.push_back(a[i]);
}
// 建堆
// O(N*lgN)
for (int i = (_a.size()-2)/2; i >= 0; --i)
{
AdjustDown(i); // O(lgN)
}
}
void Push(const T& x)
{
_a.push_back(x);
AdjustUp(_a.size()-1);
}
void Pop()
{
assert(!_a.Empty());
swap(_a[0], _a[_a.size()-1]);
_a.pop_back();
AdjustDown(0);
}
void AdjustUp(int child)
{
Compare com;
int parent = (child-1)/2;
while (child > 0)
{
//if (_a[child] > _a[parent])
if (com(_a[child],_a[parent]))
{
swap(_a[parent], _a[child]);
child = parent;
parent = (child-1)/2;
}
else
{
break;
}
}
}
void AdjustDown(int root)
{
Compare com;
int parent = root;
int child = parent*2+1;
while (child < _a.size())
{
// 选出大的那一个孩纸
if (child+1 < _a.size() && com(_a[child+1],_a[child]))
//if (child+1 < _a.size() && _a[child+1] > _a[child])
{
++child;
}
if (com(_a[child],_a[parent]))
//if (_a[child] > _a[parent])
{
swap(_a[child], _a[parent]);
parent = child;
child = child*2+1;
}
else
{
break;
}
}
}
size_t Size()
{
return _a.size();
}
bool Empty()
{
return _a.Empty();
}
T& Top()
{
assert(_a.size() > 0);
return _a[0];
}
private:
vector<T> _a;
};
void AdjustDown(int*heap,size_t n,int root)
{
assert(heap);
int parent = root;
int child = parent*2+1;
while(child < n)
{
if(child+1<n && heap[child+1] > heap[child])
{
++child;
}
if(heap[child] > heap[parent])
{
swap(heap[child],heap[parent]);
parent = child;
child = parent*2+1;
}
else
{
break;
}
}
}
void HeapSort(int* a,size_t n)
{
//建堆
for(int i =(n-2)/2;i>= 0;--i)
{
AdjustDown(a,n,0);
}
size_t end = n-1;
while(end > 0)
{
swap(a[0],a[end]);
AdjustDown(a,end,0);
--end;
}
}
void TestHeap()
{
int a[] = {10,11, 13, 12, 16, 18, 15, 17, 14, 19};
Heap<int> hp1(a, sizeof(a)/sizeof(a[10]));
Heap<int, Less<int>> hp2(a, sizeof(a)/sizeof(a[10]));
hp1.Push(78);
}