这次我们来模拟实现堆,首先堆是一个完全二叉树,每个元素都有一个关键码,储存相应的数据,堆分为最大堆和最小堆。
最大堆:最大堆任意一个节点都大于它左右孩子的关键码,堆顶元素最大。
最小堆:最小堆任意一个节点都小于它左右孩子的关键码,堆顶元素最小。
因此我们得出以下结论:
堆存储在下标为0开始计数的数组中,因此在堆中给定小标为i的结点时:
1、如果i=0,结点i是根节点,没有双亲节点;否则结点i的双亲结点为结点(i-1)/2
2、如果2*i+1>n-1,则结点i无左孩子,否则结点i的左孩子为结点2*i+1
3、如果2*i+2>n-1,则结点i无右孩子,否则结点i的右孩子为结点2*i+2
堆的创建:
最小堆与最大堆
首先我们来分析下堆所支持的操作:
template<class T, class Compare = Less<T>>//这里第二个参数是一个比较器,Less或者是Greater
class Heap
{
public:
Heap();
Heap(const T array[], size_t size);
void Insert(const T& data);
void Remove(); //插入
size_t Size()const; //移除
bool Empty()const; //判断堆是否为空
const T& Top()const; //堆顶元素
protected:
void _AdjustDown(size_t parent); //向下调整
void _AdjustUp(size_t child); //向上调整
private:
vector<T> _heap;
};
代码如下:
template<class T>
struct Less//小堆的实现
{
bool operator()(const T& left, const T& right)//重载()
{
return left < right;
}
};
template<class T>
struct Greater//大堆的实现
{
bool operator()(const T& left, const T& right)
{
return left > right;
}
};
2、堆的生成
template<class T, class Compare = Less<T>>//这里第二个参数是一个比较器,Less或者是Greater
class Heap
{
public:
Heap()
{}
Heap(const T array[], size_t size)
{
_heap.reserve(size);
for (size_t i = 0; i < size; i++)
{
_heap.push_back(array[i]);
}
for (int j = (_heap.size() - 2) / 2; j >= 0; j--)
{
_AdjustDown(j);
}
}
};
3、向上向下调整操作
堆的向下调整算法和向上调整算法是堆的核心两个算法,它们的作用为:
堆的向下调整算法:用于建立堆,可以自行选择建立大堆或者建立小堆。
堆的向上调整算法:用于插入元素的时候使用。
void _AdjustDown(size_t parent)
{
assert(parent);
assert(!_heap.empty());
size_t child = parent * 2 + 1;
while (parent < _heap.size())
{
Compare com;
if (child + 1<_heap.size()&& com(_heap[child + 1], _heap[child]))
{
++child;
}
if (child<_heap.size() && com(_heap[child], _heap[parent]))
{
swap(_heap[child], _heap[parent]);
parent = child;
child = parent * 2 + 1;
}
else
break;
}
}
void _AdjustUp(size_t child)
{
assert(!_heap.empty());
while(child)
{
Compare com;
size_t parent = (child - 1) / 2;
if (com(_heap[child], _heap[parent]))
{
swap(_heap[child], _heap[parent]);
child = parent;
}
else
break;
}
}
下面给出完整代码:
#include <vector>
#include <assert.h>
using namespace std;
template<class T>
struct Less
{
bool operator()(const T& left, const T& right)
{
return left < right;
}
};
template<class T>
struct Greater
{
bool operator()(const T& left, const T& right)
{
return left > right;
}
};
// 小堆
template<class T, class Compare = Less<T>>
class Heap
{
public:
Heap()
{}
Heap(const T array[], size_t size)
{
_heap.reserve(size);
for (size_t i = 0; i < size; i++)
{
_heap.push_back(array[i]);
}
for (int j = (_heap.size() - 2) / 2; j >= 0; j--)
{
_AdjustDown(j);
}
}
void Insert(const T& data)
{
assert(data);
assert(!_heap.empty());
_heap.push_back(data);
_Adjustup(_heap.size() - 1);
}
void Remove()
{
assert(!_heap.empty());
swap(_heap[0], _heap[size() - 1]);
_heap.pop_back();
_AdjustDown(0);
}
size_t Size()const
{
return _heap.size();
}
bool Empty()const
{
return _heap.empty();
}
const T& Top()const
{
assert(!_heap());
return _heap[0];
}
protected:
//堆的插入
void _AdjustDown(size_t parent)
{
assert(parent);
assert(!_heap.empty());
size_t child = parent * 2 + 1;
while (parent < _heap.size())
{
Compare com;
if (child + 1<_heap.size()&& com(_heap[child + 1], _heap[child]))
{
++child;
}
if (child<_heap.size() && com(_heap[child], _heap[parent]))
{
swap(_heap[child], _heap[parent]);
parent = child;
child = parent * 2 + 1;
}
else
break;
}
}
void _AdjustUp(size_t child)
{
assert(!_heap.empty());
while(child)
{
Compare com;
size_t parent = (child - 1) / 2;
if (com(_heap[child], _heap[parent]))
{
swap(_heap[child], _heap[parent]);
child = parent;
}
else
break;
}
}
private:
vector<T> _heap;
};