排序算法学习

前言

参考文章:http://blog.csdn.net/hguisu/article/details/7776068 

文章中对算法的解释非常详细,这里只做个人总结和部分算法代码 使用的平台为unity,用c#编写 ,其中代码中涉及的数学方法为unity封装后的方法


插入排序


直接插入排序


    /// <summary>
    /// 直接插入排序 (使用List结构)
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    List<int> Sort_Zhijiecharu(List<int> data) 
    {
        //从小到大
        for (int i = 1; i < data.Count; i++)
        {
            int temp = data[i];
            int j = i - 1;
            if (data[i]< data[i-1])// 如果有调整需要
            {
                while (temp < data[j])//向前遍历,一直找到比当前元素小的数的下标
                {
                    j--;
                    if (j < 0) break;//防止下标越界
                }
                data.RemoveAt(i);
                data.Insert(j+1, temp);//将当前元素,插入到后面
            } 
        }
        return data;
    }


希尔排序


    /// <summary>
    /// 希尔排序
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    int[] Sort_Sell(int[] data) 
    {
        int dk = data.Length;
        while (true)
        {
            dk = Mathf.CeilToInt(dk / 2f);
            data = Sort_Sell_Zhijiecharu(data, dk);
            if (dk == 1) break;
        }
        return data;
    }

    /// <summary>
    /// 希尔排序中使用到的直接插入
    /// </summary>
    /// <param name="data"></param>
    /// <param name="dk">下标的增量 直接插入排序dk=1</param>
    /// <returns></returns>
    int[] Sort_Sell_Zhijiecharu(int[] data,int dk)
    {
        //从小到大
        int temp = 0;
        for (int x = 0; x < dk; x++)//遍历 通过dk分成的子序列
        {
            for (int i = x + dk; i < data.Length; i += dk)//遍历子序列
            {
                int j = i - dk;
                temp = data[i];
                for (; j >= 0 && temp < data[j]; j -= dk)//向前遍历 如果前面元素>当前元素 
                {
                    data[j + dk] = data[j];//前面元素后移
                }
                data[j + dk] = temp;//将当前元素插入到目标位置
            }
        }
        return data;
    }


选择排序


简单选择排序


    /// <summary>
    /// 简单排序
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    int[] Sort_Jiandan(int[] data) 
    {
        int pos = 0;
        int temp = 0;
        for (int i = 0; i < data.Length; i++)
        {
            temp = data[i];
            pos = i;
            //遍历后面的数据,从中找出一个最小的
            for (int j = i+1; j < data.Length; j++)
            {
                if (data[j]<temp)
                {
                    temp = data[j];
                    pos = j;
                }
            }
            //交换位置
            data[pos] = data[i];
            data[i] = temp;
        }
        return data;
    }


堆排序


    /// <summary>
    /// 调整为大顶堆(或 小顶堆)
    /// </summary>
    /// <param name="H">数组</param>
    /// <param name="parent">父节点</param>
    /// <param name="length">数组长度</param>
    void HeapAdjust(int[] H, int parent, int length)
    {
        //构建一个大顶堆,即堆顶为最大元素
        int tmp = H[parent];
        int child = 2 * parent + 1; //左孩子结点的位置。(i+1 为当前调整结点的右孩子结点的位置)  
        while (child < length)//经过循环,保证以H[parent]为根结点的子数为一个大顶堆
        {
            if (child + 1 < length && H[child] < H[child + 1])
            {   //如果右孩子大于左孩子(找到比当前待调整结点大的孩子结点)  
                child++;
            }
            if (H[parent] < H[child])
            {   //如果较大的子结点大于父结点  
                H[parent] = H[child]; // 那么把较大的子结点往上移动,替换它的父结点  
                parent = child;       // 重新设置parent,即待调整的下一个结点的位置  
                child = 2 * parent + 1;
            }
            else
            {   //如果当前待调整结点大于它的左右孩子,则不需要调整,直接退出  
                break;
            }
            H[parent] = tmp;//当前待调整的结点放到比其大的孩子结点位置上  
        }
    }

    /// <summary>
    /// 创建初始堆
    /// </summary>
    /// <param name="H"></param>
    /// <param name="length"></param>
    void BuildingHeap(int[] H, int length)
    {
        //最后一个有孩子的节点的位置 i=  (length -1) / 2  
        for (int i = (length - 1) / 2; i >= 0; --i)
        {   
            HeapAdjust(H, i, length);
        }      
    }

    /// <summary>
    /// 堆排序
    /// </summary>
    /// <param name="H"></param>
    /// <param name="length"></param>
    void Sort_Heap(int[] H, int length)
    {
        //初始堆  
        BuildingHeap(H, length);
        //从最后一个元素开始对序列进行调整  
        for (int i = length - 1; i > 0; --i)
        {
            //交换堆顶元素H[0]和堆中最后一个元素  
            int temp = H[i]; H[i] = H[0]; H[0] = temp;
            //每次交换堆顶元素和堆中最后一个元素之后,都要对堆进行调整  
            HeapAdjust(H, 0, i);
        }
    }


交换排序


冒泡排序


    /// <summary>
    /// 冒泡排序
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    int[] Sort_MaoPao(int[] data)
    {
        //从小到大排序
        DateTime start = DateTime.Now;
        int count = data.Length;
        //冒泡 
        for (int i = 0; i < count - 1; i++)
        {
            for (int j = 0; j < count - 1 - i; j++)
            {
                if (data[j] > data[j + 1])
                {
                    int temp = data[j + 1];
                    data[j + 1] = data[j];
                    data[j] = temp;
                }
            }
        }
        TimeSpan dur = DateTime.Now - start;
        print(dur.Milliseconds);
        return data;
    }


快速排序


    /// <summary>
    /// 快速排序
    /// </summary>
    /// <param name="a"></param>
    /// <param name="low"></param>
    /// <param name="high"></param>
    void Sort_Quick(int[] a, int low, int high)
    {
        if (low < high)
        {
            int privotLoc = Partition(a, low, high);  //将表一分为二  
            Sort_Quick(a, low, privotLoc - 1);        //递归对低子表递归排序  
            Sort_Quick(a, privotLoc + 1, high);       //递归对高子表递归排序  
        }
    }

    int Partition(int[] a, int low, int high)
    {
        int privotKey = a[low];//基准元素  
        int temp = 0;
        while (low < high)
        {
            //从表的两端交替地向中间扫描  
            while (low < high && a[high] >= privotKey) --high;//从high 所指位置向前搜索,至多到low+1 位置。将比基准元素小的交换到低端  
            //位置互换
            temp = a[high];
            a[high] = a[low];
            a[low] = temp;
            while (low < high && a[low] <= privotKey) ++low;
            //位置互换
            temp = a[high];
            a[high] = a[low];
            a[low] = temp;
        }
        return low;
    }


时间复杂度




稳定性


排序算法的稳定性:若待排序的序列中,存在多个具有相同关键字的记录,经过排序, 这些记录的相对次序保持不变,则称该算法是稳定的

若经排序后,记录的相对次序发生了改变,则称该算法是不稳定的。 

稳定性的好处:排序算法如果是稳定的,那么从一个键上排序,然后再从另一个键上排序,第一个键排序的结果可以为第二个键排序所用。

基数排序就是这样,先按低位排序,逐次按高位排序,低位相同的元素其顺序再高位也相同时是不会改变的。另外,如果排序算法稳定,可以避免多余的比较


如何选择排序算法


排序算法简单的讲分为两种 空间换时间,时间换空间

根据数据量的多少,数据量的大小,排序速度要求,内存空间大小,稳定性要求,

具体内容 上述文章最后有讲,比较详细



  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值