原理:
有N个元素,从层数最多的根节点开始,从右到左逐层向上,不断的构造一个大根堆,当最上层的根为最大的元素的时候,和这个树最后一个子节点交换。然后在对N-1个元素继续构造大根堆。
举例:
0 1 2 3 4 5 6 7 8 9 (下标)
12 | 5 | 57 | 2 | 31 | 90 | 32 | 95 | 76 |
对应转换成树形结构:
为了方便我之后用数组表示了:
从根2的开始:比较根的左右子节点95大于76,且95大于2,95和2进行交换。
12,5,57,95,31,90,32,,2,76
从根57的开始:90大于32且大于根,90与57进行交换。
12,5,90,95,31,57,32,2,76
从根5的开始:95大于31且大于根,90和5进行交换。
12,95,90,5,31,57,32,2,26
从根5的开始:76大于2且大于根,76和5进行交换。
12,95,90,76,31,57,32,2,5
从根12的开始:95大于90且大于根,95和12进行交换。
95,12,90,76,31,57,32,2,5
从根12的开始:76大于31且大于根,76和12进行交换。
95,76,90,12,31,57,32,2,5
从根12的开始:5大于2且小于根,不进行交换。
95,76,90,12,31,57,32,2,5
此时95为最大的根,95和最后的一片叶子节点进行交换。95不再参与堆排序。剩下的元素继续堆排序。
5,76,90,12,31,57,32,2,95
从根12的开始,2小于根。不交换。
从根90的开始,57大于32小于根。不交换。
从根76的开始,31大于12小于根。不交换。
从根5的开始,90大于76且大于根。90和5进行交换。
90,76,5,12,31,57,32,2,95
从根5的开始,57大于32且大于根,57和5进行交换。
90,76,5,12,31,57,32,2,95
此时90为最大的根,90和最后的一片叶子节点进行交换。90不再参与堆排序。剩下的元素继续堆排序。
从根5的开始,57大于32且大于根,57和5进行交换。
2,76,57,12,31,5,32,90,95
从根76的开始,31大于12且小于根。不交换。
从根2的开始,76大于57且大于根。76和2进行交换。
76,2,57,12,31,5,32,90,95
从根2的开始,31大于12且大于根。31和2进行交换。
76,31,57,12,2,5,32,90,95
此时76为最大的根,76和最后的一片叶子节点进行交换。76不再参与堆排序。剩下的元素继续堆排序。
32,31,57,12,2,5,76,90,95
从根57的开始,5小于根。不交换。
从根31的开始,12大于2且小于根。不交换。
从根32的开始,57大于31且大于根。57和32进行交换。
57,31,32,12,2,5,76,90,95
从根32的开始,5小于根,不交换。
此时57为最大的根,57和最后的一片叶子节点进行交换。57不再参与堆排序。剩下的元素继续堆排序。
5,31,32,12,2,57,76,90,95
从根31的开始,12大于2且小于根,不交换。
从根5的开始,32大于31且大于根,32和5进行交换。
32,31,5,12,2,57,76,90,95
此时32为最大的根,32和最后的一片叶子节点进行交换。32不再参与堆排序。剩下的元素继续堆排序。
2,31,5,12,32,57,76,90,95
从根31的开始,12小于根不交换。
从根2的开始,31大于5且大于根,31和2进行交换。
31,2,5,12,32,57,76,90,95
从根2的开始,12大于根,12和2进行交换。
31,12,5,2,32,57,76,90,95
2,12,5,31,32,57,76,90,95
从根2的开始,12大于5且大于根,12和2进行交换。
12,2,5,31,32,57,76,90,95
此时12为最大的根,12和最后的一片叶子节点进行交换。12不再参与堆排序。剩下的元素继续堆排序。
5,2,12,31,32,57,76,90,95
从根5的开始,2小于根。不交换。
此时5为最大的根,5和最后的一片叶子节点进行交换。5不再参与堆排序。
2,5,12,31,32,57,76,90,95
代码:
void HeapAdjust(int a[], int s, int nlen)
{
int temp = a[s];
for (int i = 2 * s; i <= nlen; i *= 2)
{
if (i < nlen && a[i] < a[i + 1])
{
i++;
}
if (temp > a[i])
{
break;
}
a[s] = a[i];
s = i;
}
a[s] = temp;
}
void HeapSort(int a[], int nlen)
{
for (int i = nlen / 2; i > 0; --i)
{
HeapAdjust(a, i, nlen);
}
for (int i = nlen; i > 1; --i)
{
a[1] ^= a[i];
a[i] ^= a[1];
a[1] ^= a[i];
HeapAdjust(a, 1, i-1);
}
}
总结:
堆排序是不稳定的排序算法,时间复杂度应该为重建堆加调整堆,时间复杂度为O(Nlog2N)。