算法:堆排序

1、简介

  堆排序,是一种选择排序,时间复杂度是 O(nlg(n)) ,具有空间原址性(任何时候都只需要常数个额外的元素空间存储临时数据)。同时,堆引入了另一种算法设计技巧:“堆”数据结构。
  (二叉)堆是一个数组,被看成一个近似的完全二叉树。每一个节点对应数组中的一个元素,除底层外,该树为完全充满的二叉树。任何一非叶节点满足性质:
   Keyi<=Key2i+1Keyi<=Key2i+2   大顶堆
或者 Keyi>=Key2i+1Keyi>=Key2i+2   小顶堆
  矩阵 A=[1614108793241] 堆的表示如下(注:图片来自《算法导论》)
  算法:堆排序_第1张图片

2、调整堆

  按常理说,应该怎样建堆,但是仔细对比,发现堆算法的核心就是保持这个堆是大顶堆(小顶堆)。建堆就是使一个堆(数组)调整成大顶堆(小顶堆),堆的排序算法也是需要不停的调整堆的。维护对通过让 A[i] 的值在最大堆(小顶堆)中“逐级下降”,从而使得以下标 i 为根节点的子树重新遵循大顶堆(小顶堆)的性质。
  算法:堆排序_第2张图片
  算法
  1、从A[i]、A[2i]和A[2i+1]中选取最大(最小)的,下标存储在largest中。
  2、如果A[i]是最大的,那么以i为根结点的子树已经是最大堆,程序结束。
  3、否则,最大元素是i的某个孩子借点,则交换A[i]和A[largest]的值。子树又有可能违反大顶堆(小顶堆)的性质,递归调用maxHeapify.

void swap(int* M, int i, int j){
    //交换向量中的元素
    int temp;
    temp = M[i];
    M[i] = M[j];
    M[j] = temp;
}

//A[i]、A[2i]和A[2i+1]中选取最大
void maxHeapify(int* M, int i, int length){
    int l = 2 * i;  //左子树下标
    int r = 2 * i + 1;//右子树下标
    int largest;

    if(l <= length && M[l]>M[i]){
        largest = l;
    }
    else{
        largest = i;
    }
    if(r <= length && M[r] > M[largest]){
        largest = r;
    }

    //交换A[i]和A[largest]的值,递归调用maxHeapify.
    if(largest != i){
        swap(M, i, largest);
        maxHeapify(M, largest, length);
    }
}

3、建堆

  建堆,使用的是自底向上的方法,利用上述维护堆程序maxHeapify把一个大小为length的数组转化为最大堆。算法是从最后一个堆(有可能只要两个结点,且根节点下标为 i1=length/2 )开始调整,调整倒数第二个堆,……,一直往上调整(第j次的根节点下标为 ij=length/2j+1 ,直到根节点。
  
算法:堆排序_第3张图片
算法:堆排序_第4张图片
算法:堆排序_第5张图片

void buildMaxHeap(int* M, int length){
    int i;
    for(i = length/2; i >= 0; --i){
        maxHeapify(M, i, length-1);
    }
}

4、堆排序算法

  初始时,先利用建堆将数组建成大顶堆,将最大的值,即A[0]输出,并将堆中最后一个数放到A[0]中,调整堆使其再次变为大顶堆。直到该堆为空(下面算法中为堆的长度为0).
  算法:堆排序_第6张图片
  算法:堆排序_第7张图片
  算法:堆排序_第8张图片

void heapSort(int* M, int length){
    buildMaxHeap(M, length);
    int i;
    for(i = length; i > 0; --i){
        swap(M, 0, i);
        --length;
        maxHeapify(M, 1, length-1);
    }

}

5、测试

#include "stdio.h"
void show(int M[], int length){
    int i;
    for(i = 0; i < length; ++i){
        printf("%d ", M[i]);
    }
}

//将上述代码粘贴在这里。

void main(){
    int A[4] = { 2, 4, 7, 1};
    int length = sizeof(A) / sizeof(A[0]);
    //测试建堆
    show(A, length);
    printf("\n");
    buildMaxHeap(A, length);
    show(A, length);
    printf("\n");

    //测试堆排序
    show(A, length);
    printf("\n");
    heapSort(A, length);
    show(A, length);
    printf("\n");
}

参考文献:
《算法导论》
《C++Primer》
http://blog.csdn.net/morewindows/article/details/6709644/
http://www.cnblogs.com/dolphin0520/archive/2011/10/06/2199741.html

你可能感兴趣的:(c语言,堆排序,算法,数据结构&算法)