堆排序

    /*
    ary是存储记录的数组, start是需要调整为大顶堆的根记录下标, end是
    它的最后一个叶子记录的下标。
    注意,传入的start到end之间的记录,除去根记录,根记录的左右子二叉树都
    是大顶堆, 要完全符合大顶堆的性质调用此函数才有效。
    下面函数要做的就是调整以start为根记录,end为最后一个叶子记录的完全二叉树为大顶堆。
    */
void Heapify(int ary[], unsigned int start, unsigned int end)
{
    unsigned int left = 0;
    unsigned int right = 0;
    unsigned int max = 0;
    left = start * 2;
    right = start * 2 + 1;
    /* 如果存在左子记录 */
    while (left <= end)
    {
        /* 左右子记录中,先默认左子记录的关键字值最大,保存其下标 */
        max = left;
        /* 如果左右子记录都存在,改写max使其保存了拥有最大关键字值记录的下标 */
        if (right <= end)
        {
            if (ary[left] < ary[right])
            {
                max = right;
            }
            else
            {
                max = left;
            }
        }
        /* 现在max中是保存了左右子记录中(假设存在)关键字值最大的下标 */
        if (ary[start] < ary[max])
        {
            /* 根记录的关键字值小于左右子记录中关键字值最大的 */
            ary[0] = ary[max];
            ary[max] = ary[start];
            ary[start] = ary[0];
            /* 从被交换的子记录中开始调整 */
            start = max;
        }
        else
        {
            /* 二叉树符合大顶堆性质, 调整结束 */
            break;
        }
        left = start * 2;
        right = start * 2 + 1;
    }
    /* 调整到最二叉树的最后一个叶子结点上, 二叉树也符合大顶堆性质, 调整结束 */
}

/* 进行堆排序, 完成后ary中的记录下标从1到size,它们的关键字值是非递减的 */    
void HeapSort(int ary[], unsigned int size)
{
    /* 建堆 */
    BuildHeap(ary, size);
    for (unsigned int i = size; i > 0; i--)
    {
        /* 把根记录和最后一个叶子记录交换 */
        ary[0] = ary[1];
        ary[1] = ary[i];
        ary[i] = ary[0];
        /*
        调整从1到i- 1组成的二叉树为大顶堆。
        注意:
        交换只是破坏了以ary【1】为根的二叉树大顶堆性质, 它的左右
                  子二叉树还是具  备大顶堆性质。
        */
        Heapify(ary, 1, i - 1);
    }
}

    /*
    调整整棵二叉树(完全无序状态)使之成为大顶堆。
    策略:
    首先这课二叉树的结构是完全二叉树, 我们可以从最后一个非叶子记录调整,
         直到整棵二叉树的根记录。
    比如二叉树有size个结点记录, 那么最后一个非叶子结点的下标就
         是size / 2(取整),   我们就从size / 2, size / 2 - 1, ... ,  
    直到调整以1为下标的整棵二叉树为大顶堆。
    因为以最后一个叶子记录为根的二叉树必定符合调用函数Heapify的条件,
         位于同一层的非叶子结点必定也符合调用条件,Heapify函数处理完后这一层后,
         上一层的非叶子记录对应的二叉树也符合了调用条件,
    这样直到以整棵二叉树的根(即ary【1】)记录为根的二叉树也符合大顶堆的性质,
         整个大顶堆就建立起来。
    现在整棵二叉树的根记录就是该记录集中关键字值最大的记录。
    */
void BuildHeap(int ary[], unsigned int size)
{
    /* 传入下标为i(size / 2 >= i >= 1)的记录为根,
            下标为size的最后一个叶子记录的二叉树进行调整 */
    for (unsigned int i = size / 2; i > 0; i--)
    {
        Heapify(ary, i, size);
    }
}

    /*
    算法分析:
    1.堆排序的时间,主要由建立初始堆和反复重建堆这两部分的时间开销构成,
           它们均是通过调用Heapify实现的。
     堆排序的最坏时间复杂度为O(n * lgn)。堆排序的平均性能较接近于最坏性能。
      BuildHeap最坏情况下时间复杂度为O(n),但是for循环在最坏情况下却
           要O(n * lgn)的时间。

    2.由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。

    3.堆排序是就地排序,辅助空间为O(1)。

    4.它是不稳定的排序方法。
    */

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值