排序算法七:选择排序之堆排序

声明:引用请注明出处http://blog.csdn.net/finish_dream/article/details/70231474


引言

之前已经讲过排序算法系列的插入排序,交换排序。本片文章主要讲解堆排序。


排序相关的基本概念

  • 排序:将一组杂乱无章的数据按一定的规律顺次排列起来。

    • 数据表(data list):它是待排序对象的有限集合。
    • 排序码(key):通常对象有多个属性域,即多个数据成员组成,其中有一个属性域,可用来区分对象,作为排序依据。该域即为排序
      码,每个数据表用哪个属性域作为排序码,要视具体的应用需要而定。
  • 分类

    • 内排序:指在排序期间数据对象全部存放在内存的排序;
    • 外排序:指在排序期间全部对象个数太多,不能同时存放在内存,必须根据排序过程的要求,不断在内、外存之间移动的排序。

排序的分析

排序算法的稳定性

如果在对象序列中有两个对象r[i]和r[j] ,它们的排序码k[i]==k[j] 。如果排序前后,对象r[i]和r[j] 的相对位置不变,则称排序算法是稳定的;否则排序算法是不稳定的。

排序算法的评价

时间开销

  • 排序的时间开销可用算法执行中的数据比较次数数据移动次数来衡量。
  • 算法运行时间代价的大略估算一般都按平均情况进行估算。对于那些受对象排序码序列初始排列及对象个数影响较大的,需要按最好情况和最坏情况进行估算。

空间开销

算法执行时所需的附加存储。


堆排序

堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。

C#代码

    /// <summary>
    /// 交换x,y数值
    /// </summary>
    /// <param name="x">元素1</param>
    /// <param name="y">元素2</param>
    private static void Swap(ref int x, ref int y)
    {
        int tmp = x;
        x = y;
        y = tmp;
    }
    /// <summary>
    /// 最大堆调整
    /// </summary>
    /// <param name="array">待排序数组</param>
    /// <param name="start">开始元素</param>
    /// <param name="end">结束元素</param>
    private static void MaxHeapify(ref int[] array, int start, int end)
    {
        //建立父节点和子节点指针
        int dad = start;
        int son = dad * 2 + 1;
        while (son <= end)//子节点在指定范围内才进行比较
        {
            if (son + 1 <= end && array[son] < array[son + 1])//先比较两个子节点大小,选择最大的
                son++;
            if (array[dad] > array[son])//如果父节点大于子节点代表调整完毕,直接跳出函数
                return;
            else
            {   //否则交换父子内容,再继续子节点和孙节点内容
                Swap(ref array[dad], ref array[son]);
                dad = son;
                son = dad * 2 + 1;
            }
        }
    }
    /// <summary>
    /// 堆排序
    /// </summary>
    /// <param name="array">待排序数组</param>
    /// <returns></returns>
    public static int[] HeapSort(int[] array)
    {
        if (array.Length > 0)
        {
            int num = array.Length;
            //初始化i从最后一个父节点开始调整
            for (int i = (num / 2 - 1); i >= 0; i--)
            {
                MaxHeapify(ref array, i, num - 1);
            }
            //先将堆的根节点和已排好元素的前一位做交换,再从新调整,直到调整完毕
            for (int i = num - 1; i > 0; i++)
            {
                Swap(ref array[0], ref array[i]);
                MaxHeapify(ref array, 0, i - 1);
            }
            return array;
        }
        else
        {
            throw new Exception("待排序数组大小不能小于0");
        }
    }

算法分析

堆排序的平均时间复杂度为 O ( n l o g n ),空间复杂度为 Θ ( 1 ) 。


完整代码被我放在了Github上,感兴趣的可以下下来看一下https://github.com/Finish-Dream/DSAlgorithm

原文地址:https://www.cnblogs.com/haxianhe/p/9271048.html