堆(Heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵完全二叉树的数组对象。
中文名
堆外文名
heap
定 义
一类数据结构的统称
堆(heap)是计算机科学中一类特殊的数据结构的统称。堆通常是一个可以被看做一棵树的数组对象。堆总是满足下列性质:堆中某个结点的值总是不大于或不小于其父结点的值;
堆总是一棵完全二叉树。
将根结点最大的堆叫做最大堆或大根堆,根结点最小的堆叫做最小堆或小根堆。常见的堆有二叉堆、斐波那契堆等。
堆是非线性数据结构,相当于一维数组,有两个直接后继。
堆的定义如下:n个元素的序列{k1,k2,ki,…,kn}当且仅当满足下关系时,称之为堆。
(且)或者(), ()
若将和此次序列对应的一维数组(即以一维数组作此序列的存储结构)看成是一个完全二叉树,则堆的含义表明,完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值。由此,若序列{k1,k2,…,kn}是堆,则堆顶元素(或完全二叉树的根)必为序列中n个元素的最小值(或最大值)。
堆STL
编辑
语音
堆的STL包含于#include
头文件中。
堆的STL支持以下的基本操作:make_heap(first, last, comp);
建立一个空堆;push_heap(first, last, comp);
向堆中插入一个新元素;top_heap(first, last, comp);
获取当前堆顶元素的值;sort_heap(first, last, comp);
对当前堆进行排序;
堆算法思想
编辑
语音
不必将值一个个地插入堆中,通过交换形成堆。假设一个小根堆的左、右子树都已是堆,并且根的元素名为 ,其左右子结点为 和 ,这种情况下,有两种可能:
(1) 并且 ,此时堆已完成;
(2) 或者 ,此时 应与两个子女中值较小的一个交换,结果得到一个堆,除非 仍然大于其新子女的一个或全部的两个。这种情况下,我们只需简单地继续这种将 “拉下来”的过程,直至到达某一个层使它小于它的子女,或者它成了叶结点。
堆筛选法
编辑
语音
首先将要排序的所有关键码放到一棵完全二叉树的各个结点中(这时的完全二叉树并不具备堆的特性)。显然,所有的结点 都没有子女结点,因此以这样的 为根的子树已经是堆,然后从 的结点Ki开始,逐步把以为根的子树排成堆,直到以K0为根的子树排成堆,就完成了建堆过程。
在考虑将以 为根的子树排成堆时,以 为根的子树已经是堆,所以这时如果有 和 ,则不必改变任何结点的位置,以 为根的子树就已经是堆;否则就要适当调整子树中结点的位置以满足堆的定义。由于Ki的左、右子树都已经是堆,根结点是堆中最小的结点,所以调整后 的值必定是原来 和 中较小的一个。假设 较小,将 与 交换位置,这样调整后,,并且以 为根的子树原来已经是堆,不必再作任何调整,只有以为根的子树由于的值已经发生变化(与交换了),所以有可能不满足堆的定义(当的左、右子树已经是堆)。这时可重复上述过程,考虑将以为根的子树排成堆。如此一层一层递推下去,最多可以一直进行到树叶。由于每步都保证将子树中最小的结点交换到子树的根部,所以这个过程是不会反馈的。它就像过筛一样,把最小的关键码一层一层选择出来。
堆建堆效率
编辑
语音
个结点的堆,高度。根为第0层,则第层结点个数为,考虑一个元素在堆中向下移动的距离,这种算法时间代价为
由于堆有层深,插入结点、删除普通元素和删除最小元素的平均时间代价和时间复杂度都是
。
堆代码实现
编辑
语音
c++实现#pragma once
template
class JBMinHeap
{
private:
//申请堆空间
T *_minHeap = NULL;
int _index,_maxSize;
public:
JBMinHeap(int maxSize) {
_maxSize = maxSize;
_minHeap = new T[_maxSize];
_index = -1;
}
JBMinHeap(JBMinHeap &h) {
_index = h._index;
_maxSize = h._maxSize;
_minHeap = new T[_maxSize];
for (int i = 0;i<_maxsize>
*_minHeap[i] = *h._minHeap[i];
}
}
~JBMinHeap() {
delete[]_minHeap;
}
//获取整个最小堆的头部指针
T * getMinHeap() {
return _minHeap;
}
//判断堆是不是空的
bool isEmpty() {
return _index == -1;
}
bool add(T x) {
if (isFull()) {
return false;
}
_index++;
_minHeap[_index] = x;
return true;
}
bool isFull() {
return _index == _maxSize;
}
//堆进行向下调整
void adjustDown(int index);
//队进行向上调整
void adjustUp(int index);
//建堆运算
void createMinHeap() {
if (isEmpty()) {
return;
}
for (int i = (_index-1)/2;i >-1;i--) {//直接从倒数第二层 逐层向下调整
adjustDown(i);
}
}
};
template
void JBMinHeap::adjustDown(int index) {
if (isEmpty()) {
return;
}
while (index<_index>
{
T temp = _minHeap[index];//将当前索引的位置的值保存下来
int oneC = 2 * index + 1;//获取到两个孩子的位置
int twoC = 2 * index + 2;
if (oneC == _index) {//若第一个孩子是整个堆最后一个位置 则直接执行交换操作并结束执行
_minHeap[index] = _minHeap[oneC];
_minHeap[oneC] = temp;
return;
}
if (twoC >_index) {//如果第二个孩子的索引位置越界 结束执行
return;
}
if (_minHeap[oneC] <= _minHeap[twoC]) {//正常情况的数据交互执行
if (temp > _minHeap[oneC]) {
_minHeap[index] = _minHeap[oneC];
_minHeap[oneC] = temp;
index = oneC;
}
else {//如果该处索引值已经是比两个孩子小 则结束循环
index = _index;
}
}
else
{
if (temp > _minHeap[twoC]) {
_minHeap[index] = _minHeap[twoC];
_minHeap[twoC] = temp;
index = twoC;
}
else
{
index = _index;
}
}
}
}
template
void JBMinHeap::adjustUp(int index) {
if (index > _index) {//大于堆的最大值直接return
return;
}
while (index>-1)
{
T temp = _minHeap[index];
int father = (index - 1) / 2;
if (father >= 0) {//如果索引没有出界就执行想要的操作
if (temp
_minHeap[index] = _minHeap[father];
_minHeap[father] = temp;
index=father;
}
else {//若果已经是比父亲大 则直接结束循环
index = -1;
}
}
else//出界就结束循环
{
index = -1;
}
}
}
VB.net实现Public Class Priority_Queue
Friend Element() As Integer
Friend point As Integer ReadOnly Property Top As Integer
Get
Try
Return Element(1)
Catch ex As Exception
Return 0
End Try
End Get
End Property
ReadOnly Property Size As Integer
Get
Return point
End Get
End Property
ReadOnly Property Empty As Boolean
Get
If point = 0 Then Return True
Return False
End Get
End Property Sub push(ByVal _ele_val As Integer)
point += 1
Element(point) = _ele_val
Dim Now As Integer = point
Dim Nxt As Integer = Now / 2
While (Now <> 1 AndAlso Element(Now) > Element(Nxt))
Swap(Element(Now), Element(Nxt))
Now = Nxt
Nxt /= 2
End While
End Sub
Sub pop()
Dim now As Integer = 1 Element(1) = Element(point)
point -= 1 While (1) Dim left As Integer = 0
Dim right As Integer = 0 If (now * 2 <= point) Then
left = Element(now * 2)
End If
If (now * 2 + 1 <= point) Then
right = Element(now * 2 + 1)
End If If (right = left And right = 0) Then
Exit Sub
End If If (Element(now)
If left > right Then
Swap(Element(now), Element(now * 2))
now *= 2
Else
Swap(Element(now), Element(now * 2 + 1))
now *= 2
now += 1
End If
Else
Exit While
End If
End While End Sub Sub New(ByVal _size As Integer)
ReDim Element(_size)
point = 0
End Sub
Protected Overrides Sub Finalize()
MyBase.Finalize()
End Sub End Class
词条图册
更多图册