堆排序是一种高效的比较排序算法,运行时间为O(nlgn)。
这种排序需要用到一种叫做(二叉)堆的数据结构,堆是一种数组对象,也可以看做一颗完全二叉树,对于任一节点,左右子节点和父节点分别可如下简单算出
PARENT(i) ((i - 1) / 2)
LEFT(i) (2 * i + 1)
RIGHT(i) (2 * i + 2)
堆分为大根堆和小根堆,分别具有如下性质:
a[PARENT(i)] >= a[i]
a[PARENT(i)] <= a[i]
本文采用大根堆说明堆排序算法的实现。
c++实现源代码如下:
#include <iostream>
using namespace std;
#include <algorithm>
#define LEFT(i) (2 * i + 1)
#define RIGHT(i) (2 * i + 2)
void _max_heapify(int *a, int i, int length)
{
int l = LEFT(i);
int r = RIGHT(i);
int largest = 0;
if (l < length && a[l] > a[i]) {
largest = l;
} else {
largest = i;
}
if (r < length && a[r] > a[largest]) {
largest = r;
}
if (largest != i) {
swap(a[largest], a[i]);
_max_heapify(a, largest, length);
}
}
void _built_heap(int *a, int length)
{
for (int i = length / 2; i >= 0; --i) {
_max_heapify(a, i, length);
}
}
void heap_sort(int *a, int length)
{
_built_heap(a, length);
int i = length - 1;
while (i >= 1) {
swap(a[0], a[length - 1]);
length -= 1;
_max_heapify(a, 0, length);
--i;
}
}
void print(int *a, int length)
{
for (int i = 0; i < length; ++i) {
cout << a[i] << endl;
}
}
int main()
{
int a[10] = {1, 3, 2, 4, 6, 5, 7, 8, 9, 0};
heap_sort(a, 10);
print(a, 10);
}
首先说明_max_heapify函数,这个函数用来保持大根堆的性质,对于给定的以下标为i节点为根的堆是大根堆,如果子节点大于i节点,则两子节点中最大的节点与i节点互换,若两子树依然如此,则递归调用此函数,注意:调用此函数时假设两子树分别为大根堆。
_built_heap函数用来建堆,因为对于length/2以后的元素都是叶子节点,可以看做单节点的大根堆,所以可以对其他节点分别调用_max_heapify函数完成整个堆的建立。为了满足_max_heapify函数的调用规则,应在数组中从后向前遍历。
heap_sort函数用来实现堆排序,因为每次建堆后第一个元素即是数组中的最大元素,所以将它放到最后即可,然后对其余元素继续此过程,直至数组剩余两个元素为止,至此排序完成。