由于前面的排序算法均存在多余比较的行为,那么如果可以记住比较的结果,效率可以进一步提高,所以就出现了堆排序。堆排序的一般步骤是,将数组构造成一个最大堆,然后交换对顶元素和数组最末端的元素,这样就破坏了最大堆的性质(每一个节点的值均大于左右子节点的值),于是需要重新调整,使得堆成为最大堆,堆排序可以在O(1)时间内获取元素的最大值。核心算法在于维护堆的性质。
void AdjustHeap(int a[], int root, int n) //root表示当前调整的节点
{
int left = root*2 + 1; //左孩子
int right = root*2 + 2; //右孩子
int maxPos = root;
if (root <= n/2) {
if (left < n && a[left] > a[maxPos]) {
maxPos = left;
}
if (right < n && a[right] > a[maxPos]) {
maxPos = right;
}
if (maxPos != root) { //获取当前节点、左右孩子三个节点中的最大者作为新的根节点
myexchange(a, root, maxPos);
AdjustHeap(a, maxPos, n); //交换后maxPos节点可能又违背了最大堆的性质,需要进一步调整
}
}
return;
}
建立最大堆的代码
void BuildHeap(int a[], int n)
{
for (int i = n/2; i >=0; i--) {
AdjustHeap(a, i, n);
}
return;
}
堆排序算法
void EX_SortHeap(int a[], int n)
{
BuildHeap(a, n);
for (int i = n - 1; i > 0; i--) {
myexchange(a, 0, i); //交换堆顶元素和数组未
AdjustHeap(a, 0, i - 1); //维持堆的性质
}
return;
}