一、什么是堆
若数组a[n] 中的元素具有如下的性质:
(1)若2*i+1<n(保证2*i+1为数组中元素),则a[i]>=a[2*i+1];
(2)若2*i+2<n(保证2*i+1为数组中元素),则a[i]>=a[2*i+2];
则数组a[n]是一个堆,即任一节点的值不小于它的左子节点的值,也不小于它的右子节点的值。
注:元素a[i]的父节点为a[(i-1)/2],其中除号为整除,且元素a[i]的两个子节点分别为a[2*i+1],a[2*i+2]
二、堆排序
对一个数组进行堆排序,首先要把数组变成一个堆,即数组的堆化,然后进行堆排序。
(1)数组的堆化
从第一个不是叶节点的节点开始调整。因为数组的最后一个元素为a[n-1],故其父节点为a[(n-1-1)/2],即a[(n-2)/2]。在如下图1中,n = 9,a[(n-2)/2] = a[3] = 68
图1 图2 图3
首先,i = 3,比较a[3] = 68的两个左右子节点,找出对大的;然后把子节点中最大的元素与a[3]比较,若a[3]小于较大的子节点,则交换,即完成以a[3]为顶点的子树的堆化,结果为图2;同理,i = 2,同理将22与42交换,可完成以a[2]为顶点的堆排序,结果为图3;当i = 1时,将26与84交换,然后再将26与68交换,使得以a[1] = 26为顶点的子树堆化,过程如下图:
图4 图5
同理,i = 0时,46与84交换,同时只需修改以a[0]为顶点的左分支,因为右分支原本就是堆,过程如下图:
图6 图7 图8
代码如下:
/*ra为需要排序的数组,l 为需要堆化的起始序号,r为需要堆化的终止序号,前提为i以下所有节点都已经堆化*/
template<typename _Tp> void sift_down(vector<_Tp> &ra, const int l, const int r)
{
int i = l;//i 表示顶端的节点
int j;
_Tp a;
while ((2 * i + 1) <= r)//若存在子节点
{
j = 2 * i + 1;
{
int i = l;//i 表示顶端的节点
int j;
_Tp a;
while ((2 * i + 1) <= r)//若存在子节点
{
j = 2 * i + 1;
//找出两个左右子节点中比较大的,定位在j处
if ((j < r) && (ra[j] < ra[j + 1]))
{
j++;
}
//看是否需要与子节点交换
if (ra[i] < ra[j])
{
a = ra[i];
ra[i] = ra[j];
ra[j] = a;
i = j;//下次从这个点开始调整
}
else
{
break;
}
}
}
(2)堆排序
根据堆的性质可知,一个堆的顶点元素a[0]是堆中的最大元素。将a[0]与a[n-1]交换,此时a[n-1]是最大的元素,然后将数组a[0]a[1].........a[n-2]堆化;同理继续将a[0]与a[n-2]交换,此时a[n-2]为数组中第二大的元素,且堆化a[0]a[1].........a[n-3];依次类推,共需n-1调整和对换,在进行第i次对调前,a[0]a[1].........a[n-i]是一个堆,当a[0]与a[n-i]对调后,a[n-i]是第i个大的节点,这时将a[0]a[1].........a[n-i-1]堆化。最后可得到一个递增的数组。
代码如下:
/*heap_sort堆排序的主题流程*/
template<typename _Tp> void heap_sort(vector<_Tp> &ra)
{
int i, j;
int n = ra.size();
//堆化数组,从第一个非叶节点开始,依次调整为堆
for (i = (n - 2) / 2; i >= 0; i--)
{
sift_down2(ra, i, n - 1);
}
//对堆进行排序
for (j = 1; j < n; j++)
{
//把ra[0]与数组的最后一个元素交换
swap(ra[0],ra[n-j]);
//堆化数组
sift_down2(ra, 0, n - j - 1);
}
return;
}
template<typename _Tp> void heap_sort(vector<_Tp> &ra)
{
int i, j;
int n = ra.size();
//堆化数组,从第一个非叶节点开始,依次调整为堆
for (i = (n - 2) / 2; i >= 0; i--)
{
sift_down2(ra, i, n - 1);
}
//对堆进行排序
for (j = 1; j < n; j++)
{
//把ra[0]与数组的最后一个元素交换
swap(ra[0],ra[n-j]);
//堆化数组
sift_down2(ra, 0, n - j - 1);
}
return;
}
第一次写博客,希望大家多多指教,共同学习!