c# list.sort 不稳定排序变为稳定排序(一)


结论

如有错,请大佬批评指正~

稳定排序:

  • 单次排序数据较少,用插入排序
  • 单次排序数据较大,用List.Sort的定制版(自己改一下)
    可以参考下图,几百以内可定义为数据较少上千上万可认为数据较大
    图(一)
    (图中单位为ms)

1.起因

因为List<T>的方便性,我在项目中常常使用,虽说知道有一定性能消耗,但没有具体研究过,直到(直到踩坑 )…在一个需要频繁排序,且需要是稳定的情况下,List.Sort()不再继续适用了。

2.可能的解决方法

一番查资料、翻书后,要么使用稳定且较快速的插入排序(含改进和二分搜索版),要么对List.Sort()进行一些限制调整。

2.0 自定义数据结构

插入排序是稳定的,嗯,但它的改进版、二分法查找版是稳定的吗?List.Sort是稳定的吗,书本和网络上有着很多混淆的答案。
对代码进行逻辑分析是第一步,但究竟什么时候稳定什么时候不稳定(稳定和不稳定是可以转换的),还是实践出真知,我们建立测试用数据结构,是否稳定一测便知:

		public class MyData
        {
            public int data;
            public int idx;
            public MyData(int data)
            {
                this.data = data;
                idx = GetIdx();
            }
        }
        public static int Idx = 0;
        static int GetIdx()
        {
            return Idx++;
        }

这里的 idx 用来检查排序前后,相同元素的相对顺序是否被改变了

2.1 插入排序
		//改进版
		static void InsertionSort_noSwap(List<MyData> arr)
        {
            MyData temp = null;
            int j;
            for (int i = 1; i < arr.Count; i++)
            {
                temp = arr[i];
                j = i - 1;
                while (j >= 0 && temp.data < arr[j].data)
                {
                    arr[j + 1] = arr[j];
                    --j;
                }
                arr[j + 1] = temp;
            }
        }
        //二分搜索法
        static void InsertionSort_BinarySearch(MyData[] arr)
        {
            for (int i = 1; i < arr.Length; i++)
            {
                MyData temp = arr[i];
                int low = 0;
                int high = i - 1;
                int mid = -1;
                while (low <= high)
                {
                    mid = low + (high - low) / 2;
                    if (arr[mid].data > temp.data)
                    {
                        high = mid - 1;
                    }
                    else
                    {
                        low = mid + 1;
                    }
                }
                for (int j = i - 1; j >= low; j--)
                {
                    arr[j + 1] = arr[j];
                }
                arr[low] = temp;
            }
        }
2.2 List.Sort()自定义

对数据结构进行扩充,定义相同元素的处理方法

		public class MyData : IComparable
        {
            public int data;
            public int idx;
            public MyData(int data)
            {
                this.data = data;
                idx = GetIdx();
            }
            public int CompareTo(object obj)
            {
                int result = 1;
                if (obj != null && obj is MyData)
                {
                    var myData = (MyData)obj;
                    result = this.data.CompareTo(myData.data);

                    if (result == 0)
                        result = this.idx.CompareTo(myData.idx);
                }
                return result;
            }
        }
        //调用时和普通的一样(升序)
        List.Sort();

3.确定解决方案

生成多个随机数组,进行时间消耗测试
测试结果及结论见文章开头。

所以针对项目,这种单次数据量小,但是会频繁排序的情况,还是使用插入排序较好。
优化后排序消耗是原来的1/2 ~ 1/3

运行的结果,这里只排了3次,每次10个(快速排序作为不稳定的排序,也放在里面作为对比)

在这里插入图片描述
在这里插入图片描述

Ps:做需求时间紧,最开始用的老方法,时间和空间消耗妥妥的大:

		static List<int> s_rank = new List<int>();
        static MyData[] m_temp;
        /// <summary>
        /// 3_Old
        /// 老方法
        /// </summary>
        /// <param name="arr"></param>
        static void OldSort(MyData[] arr)
        {
            int len = arr.Length;
            int idx = 0;
            s_rank.Clear();
            m_temp = new MyData[len];
            for (int i = 0; i < len; ++i)
            {
                if (s_rank.Contains(arr[i].data) == false)
                {
                    s_rank.Add(arr[i].data);
                }
            }

            s_rank.Sort();

            for (int s_idx = 0; s_idx < s_rank.Count; ++s_idx)
            {
                for (int i = 0; i < len; ++i)
                {
                    if (arr[i].data == s_rank[s_idx])
                    {
                        m_temp[idx] = arr[i];
                        ++idx;
                    }
                }
            }
            for (int i = 0; i < m_temp.Length; ++i)
            {
                arr[i] = m_temp[i];
            }
        }
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ShallsenSalt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值