算法学习(排序五)堆排序

堆排序引入了另一种算法设计技巧,使用了“堆”的数据结构来进行信息管理,堆是一个数组,可以看成一个近似的完全二叉树,如数组{1, 2, 3, 4, 5},可以看做为根节点为1,左孩子节点有2,右孩子节点为3的二叉树,4,5分别为2的左孩子和右孩子,因此我们通过计算可以求得:

    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] 
/** 给定位置,分别返回父节点,左孩子和右孩子的下标 */
#define PARENT(__I__) ((__I__ - 1) / 2)
#define LEFT(__I__) (2 * __I__ + 1)
#define RIGHT(__I__) ((2 * __I__) + 2)

/** 生成该节点的最大堆  @param array 给定的数组  @param index 给定的节点  @param size 堆的长度 */
void maxHeapify (int *array, int index, int size)
{
    //TODO: 1.以index为父节点,获取左孩子和右孩子的下标
    int left = LEFT(index);
    int right = RIGHT(index);

    //TODO: 2.用来存储父节点,左孩子和右孩子间的最大值的下标
    int largest;

    //TODO: 3.当仅包含父节点和一个孩子节点,且孩子节点大于父节点时,交换位置
    if (size == 2)
    {
        if (array[0] > array[1])
        {
            int temp = array[1];
            array[1] = array[0];
            array[0] = temp;
        }
    }

    //TODO: 4.当左右孩子的下标超过堆长度时,不做操作,这个也意味着index所在的节点是叶节点
    if (left >= size || right >= size)
        return;

    //TODO: 5.比较三个中的最大值,赋值给largest
    if (left < size && array[left] > array[index])
        largest = left;
    else
        largest = index;

    if (right < size && array[right] > array[largest])
        largest = right;

    //TODO: 6.如果父节点为最大值,则操作成功
    if (largest == index)
        return;

    //TODO: 7.如果父节点不是最大值,则将父节点和最大值的位置交换
    int temp = array[index];
    array[index] = array[largest];
    array[largest] = temp;

    //TODO: 8.经过交换后,堆又发生了变化,还需要查看largest为父节点的树是否最大堆
    maxHeapify(array, largest, size);
}


/** 将给定的堆转化为最大堆  @param array 给定的数组  @param size 堆的长度 */
void buildMaxHeap (int *array, int size)
{
    //TODO 1.从size / 2的位置开始往前遍历各个节点,将所有子树转化为最大堆
    for (int i = size / 2; i >= 0; i--)
        maxHeapify(array, i, size);
}


/** 堆排序  @param array 给定的数组  @param size 堆的长度 */
void sort(int *array, int size)
{
    //TODO 1.首先转化为最大堆
    buildMaxHeap(array, size);
    //TODO 2.从后往前遍历,其中做生成最大堆的操作,没遍历一次可以获得最大值
    for (int i = size - 1; i > 0; i--)
    {
        //TODO 3.生成最大堆之后,首位必定是数组中的最大值,将其和当前下标的值交换,如此,每次操作过后,大的值都往后移动
        int temp = array[i];
        array[i] = array[0];
        array[0] = temp;

        //TODO 4.生成最大堆
        maxHeapify(array, 0, i);
    }
}
点赞