首先介绍几个基本概念。
符合以下性质的二叉树被称为堆:
1.是一棵完全二叉树,也就是说,除了最低层之外,树的每一层都是满的,且最低层的节点位于左边。
2.它满足堆次序:每个节点的数据项都大于或等于其子女的数据项(或小于等于),其中满足堆次序“大于等于”为最大堆,满足“小于等于”为最小堆。
如图第一棵树是堆,第二棵树不是堆因为他不是完全树,第三棵树是完全树但不是堆,因为它不满足堆次序。
近似堆:
堆的根元素和最后一个元素交换,堆大小减一即得到一个近似堆,因为它是完全树且两个子树都是堆,它不是堆的唯一原因是树根元素并不大于或等于其子女元素。
要将近似堆转换为堆,我们首先把根和其子女中较大的那一个进行交换保证新的根比其子女大,然后继续向下迭代直至到达树的底部。
下调算法为:
/*data[begin],...,data[end]存储一个近似堆,将其调整为堆*/
(1)令 root = begin, left = 2 * root + 1 - begin //左子树的位置
(2)当left<=end做以下工作:
1.left<end且data[left] < data[left + 1], left+1 //令left为右子女
2.如果data[root] < data[left],交换data[root]和data[left],令root=left, left = 2*root + 1 - begin;
否则,过程终止。//堆次序条件满足
End while
有了以上基本概念就可以介绍堆排序了。首先排序之前我们应该将其转换为一个堆。
将任意完全二叉树转换为堆的建堆算法
/*data[begin],...,data[end]存储一棵完全二叉树,将其转换为堆*/
(1)令root = (begin + end) / 2 - 1;//最后一个非叶节点
(2)for r = root down to begin,对以data[r]为根的子树调用上述下调算法。
End for
堆排序算法
/*对data[begin],...,data[end]使用堆排序进行升序排序*/
(1)将data视为一棵完全二叉树,使用建堆算法将其转化为一个堆;
(2)当begin<end做以下工作:
i.交换data[begin],...,data[end];
ii.end减一;
iii.在begin和end之间调用下调算法;
End while
代码如下:
/*-------------------------------------------------------------------------
*data[begin],...,data[end],存储一个近似堆,只有data[begin]的值不满足堆
*次序条件,把这个近似堆堆调整为最大堆。
*-------------------------------------------------------------------------*/
template <typename ElementType>
void percolateDown(ElementType* data, int begin, int end)
{
int root = begin;
int left = 2 * root + 1 - begin;//左子树的位置
while(left <= end)
{
if(left < end && data[left] < data[left + 1]) //当前节点有两个子女且右子女比较大
{
++left; //切换到右子女
}
if(data[root] < data[left])
{
swap(data[root], data[left]);
root = left;
left = 2 * root + 1 - begin;
}
else
break;
}
}
/*---------------------------------------------------------------------
*将任意一棵完全二叉树转换为堆的建堆算法
*---------------------------------------------------------------------*/
template <typename ElementType>
void Heaplify(ElementType* data, int begin, int end)
{
int root = (end + begin) / 2 - 1;//最后一个非叶节点
while(root >= begin)
{
percolateDown(data, root, end);
--root;
}
}
template <typename ElementType>
void heapSort(ElementType* data, int begin, int end)
{
Heaplify(data, begin, end);
while(begin < end)
{
swap(data[begin], data[end]);
--end;
percolateDown(data, begin, end);
}
}