【堆的概念】
如果有一个关键码的集合K = {k0,k1, k2,…,kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一
个一维数组中,并满足:Ki<=K2*i+1 且 Ki<= K2*i+2(Ki >= K2*i+1 且 Ki >= K2*i+2) i = 0,1,2…,则称这个
堆为最小堆(或最大堆)。
最小堆:任一结点的关键码均小于等于它的左右孩子的关键码,位于堆顶结点的关键码最小。
最大堆:任一结点的关键码均大于等于它的左右孩子的关键码,位于堆顶结点的关键码最大。
在堆中,所有的记录具有称之为堆序的关系。
具有最小堆序的结点(除没有孩子的结点)之间存在小于或等于关系,从根节点到每个结
点的路径上数组元素组成的序列都是递增的。
具有最大堆序的结点(除没有孩子的结点)之间存在大于或等于关系,从根节点到每个结
点的路径上数组元素组成的序列都是递减的。
堆存储在下标为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
【堆的创建】
堆的建立有两种方式,一种是建立一个空堆,另一种是通过复制一个记录数组并对其加以调整形成一个空的堆。
下面的数组用完全二叉树表示:
将上述二叉树调整为最小堆的结构:
从结点(sizeof(arr) / sizeof(arr[0])-1)/2开始调整,将每一棵子树都调整成一棵最小堆结构.
第一次i=3,检测以i为结点的子树是否满足最小堆,如果满足则不调整,否则将其调整为最小堆。完毕之后i--(以3为下标的结点满足最小堆性质,故不需要调整)。
第二次i=2,不满足最小堆性质,故需要调整。
调整方法:a.取 i 结点左右孩子中较小的节点(5->65)。
b.与结点 i 值比较,若i>a步骤中取得值,交换i与a中选中结点的值。完毕之后i--。
第三次i=1:将i=1的子树调整为最小堆。
第四次i=0:将整棵树调整为最小堆。
【堆的插入与删除】
插入:堆的插入每次都在已经建成的而最小堆的后面插入,但插入之后,有可能破坏了对的结构,这时就需要对堆进
行重新调整。
删除:从堆中删除堆顶元素。移除堆顶元素之后,用堆的最后一个节点填补取走的堆顶元素,并将堆的实际元素个数减1。但用最后一个元素取代堆顶元素之后有可能破坏堆,因此需要将对自顶向下调整,使其满足最大或最小堆。
template<class T>
class Greater//大堆
{
public:
bool operator()(const T&left, const T&right)
{
return left >= right;
}
};
template<class T>
class Less//小堆
{
public:
bool operator()(const T&left, const T&right)
{
return left < right;
}
};
template<class T, template <class>class Compare=Less>
class Heap
{
public:
Heap()
{}
Heap(const T arr[], size_t size)
{
//_heap.resize(size);
//保存数据
for (size_t idx = 0; idx < size; ++idx)
{
_heap.push_back(arr[idx]);
}
//找最后一个非叶子节点
size_t root = (_heap.size() - 2)/2;
for (int idx = root; idx >= 0; --idx)
{
//调整idx为根的树,使其每个节点满足堆的性质
_AdjustDown(idx,size);
}
}
void Insert(const T& data)
{
_heap.push_back(data);
size_t size = _heap.size();
if (size > 1)
{
size_t size = _heap.size();
size_t root = (size - 2) / 2;
_AdjustUp(size);
}
}
void Remove()
{
assert(!Empty());//assert为假触发
size_t size = _heap.size();
if (size > 1)
{
std::swap(_heap[0], _heap[size - 1]);
_heap.pop_back();
_AdjustDown(0, size - 1);
}
else
{
_heap.pop_back();
}
}
bool Empty()const
{
return _heap.empty();
}
size_t size()
{
return _heap.size();
}
T &Top()
{
return _heap[0];
}
~Heap()
{}
public:
void _AdjustDown(size_t root, size_t size)
{
size_t parent = root;
//默认左孩子最小
size_t child = root * 2 + 1;
while (child<size)
{
if (child + 1 < size && Compare<T>()(_heap[child+1], _heap[child]))
{
child = child + 1;
}
// if (_heap[parent] > _heap[child])
if (Compare<T>()(_heap[parent], _heap[child]))
{
std::swap(_heap[parent], _heap[child]);
parent = child;
child = child * 2 + 1;
}
else{ break; }
}
}
void _AdjustUp(size_t size)
{
size_t parent = (size - 2) / 2;
size_t child = size - 1;
while (child != 0)
{
// if (_heap[child]<_heap[parent])
if (Compare<T>()(_heap[child], _heap[parent]))
{
std::swap(_heap[child], _heap[parent]);
child = parent;
parent = (child - 1) / 2;
}
else
break;
}
}
private:
std::vector<T>_heap;
};
本文详细介绍了堆数据结构的概念,包括最小堆与最大堆的特点及应用。讲解了如何在一维数组中存储堆,并提供了堆的创建、插入和删除操作的具体实现方法。
14万+

被折叠的 条评论
为什么被折叠?



