1. 源起:

KV 7.0加入列表管理功能,处理排序问题时,对空列表执行按大小、日期、长度排序发现,其中次序会发生改变,令人纳闷。

没天理呀,不应该啊!List.Sort()方法,它为什么?

对此问题深入去了解,倒发现了有趣的问题:稳固排序与非稳固排序。

2、稳固排序与非稳固排序

微软官方网站找到此段说明:

Remarks

If comparison is provided, the elements of the List<T> are sorted using the method represented by the delegate.

If comparison is null, an ArgumentNullException is thrown.

This method uses Array.Sort, which applies the introspective sort as follows:

  • If the partition size is fewer than 16 elements, it uses an insertion sort algorithm

  • If the number of partitions exceeds 2 * LogN, where N is the range of the input array, it uses a Heapsort algorithm.

  • Otherwise, it uses a Quicksort algorithm.

This implementation performs an unstable sort; that is, if two elements are equal, their order might not be preserved. In contrast, a stable sort preserves the order of elements that are equal.

On average, this method is an O(n log n) operation, where n is Count; in the worst case it is an O(n ^ 2) operation.

大意是此实现将执行不稳定排序。也就是说,如果两个元素相等,则可能不会保留其顺序。

我们建Demo做验证,用例如下:

    var list = new List<string>();
list.AddRange(new string[] { "", "", "", "" }); list.Sort((x, y) =>
{
return ;
}); foreach (string s in list)
Console.WriteLine(s);

其输出为:

验证上述结果,推测它是使用了二分法快速反序,把后半部分置前了。

可八辈的我们宁愿它输入为原始顺序3214,这个合理,但是,可是,它无耻的变了……

3、实际场景

比如,我们需要对特定的对象进行排序,如下摘取网上例子(链接)稍加修正,以做示例:

    static void Main(string[] args)
{
var p1 = new Person() { Name = "Abby", Age = };
var p4 = new Person() { Name = "Jason", Age = };
var p2 = new Person() { Name = "Bob", Age = };
var p3 = new Person() { Name = "Charlie", Age = };
var p5 = new Person() { Name = "Danielle", Age = }; var list = new List<Person>();
list.Add(p1);
list.Add(p2);
list.Add(p3);
list.Add(p4);
list.Add(p5);
list.Sort(); Console.WriteLine("Unstable List Sort:");
foreach (Person p in list)
Console.WriteLine(p); Console.ReadLine();
} class Person : IComparable
{
public string Name { get; set; }
public int Age { get; set; } public int CompareTo(object obj)
{
int result = ;
if (obj != null && obj is Person)
{
var person = (Person)obj;
result = this.Age.CompareTo(person.Age);;
}
return result;
} public override string ToString()
{
return String.Format("{0} - {1}", this.Name, this.Age);
}
}

其输出为:

其中间23岁之三项,没有按Jason、Bob、Charlie的次序来,甚至也不是倒序。

我就是想要它加入顺序不变,怎么办?

对此问题,搜出一些文章,有建议用LINQ排序因为它是稳固排序,可我们工程所用.net framework版本为2.0,不支持,只好做罢。

在stackoverflow上,碰到一群难兄难弟,诸般建议阅过,找到可用方法,加索引!

4、解决方法

且修改Person类,加入SortIndex属性如下,并修正其比较函数:

    class Person : IComparable
{
public string Name { get; set; }
public int Age { get; set; }
public int SortIndex { get; set; }
public int CompareTo(object obj)
{
int result = ;
if (obj != null && obj is Person)
{
var person = (Person)obj;
result = this.Age.CompareTo(person.Age); if (result == )
result = this.SortIndex.CompareTo(person.SortIndex);
}
return result;
}
...
}

初始化时,加入其索引:

        var p1 = new Person() { Name = "Abby", Age = , SortIndex =  };
var p4 = new Person() { Name = "Jason", Age = , SortIndex = };
var p2 = new Person() { Name = "Bob", Age = , SortIndex = };
var p3 = new Person() { Name = "Charlie", Age = , SortIndex = };
var p5 = new Person() { Name = "Danielle", Age = , SortIndex = };

输出顺序:

保留初始顺序,解决问题。

后记:

之前未曾留意,此问题发现倒是很有意思,度娘不给力,解决问题还是要google,在stackoverflow上找到有同困扰之人,得其可参考方案。

此场景,通常用于自定义数据结构比较,如KV项目之空白列表,当其可比较项相等时,应该保留其原始顺序,可是被改变了,导致寻求解决问题的方法。

但在官方方案已固定不能改变之情况下,做个曲线救国,加另一索引以固定次序,虽然看来费些点工夫,但是能解决问题,不失为好的可用方法。

参考文档:

List(T).Sort Method (Comparison(T)) (System.Collections.Generic)

C# Stable Sort : C# 411

Why does List<T>.Sort method reorder equal IComparable<T> elements?

c#: List.Sort()实现稳固排序(stable sort)的更多相关文章

  1. C#中List调用库函数sort进行升序排序

    private void button1_Click(object sender, EventArgs e) { List<int> demo2 = new List<int> ...

  2. python 排序之sort

    #coding:utf-8 #求列表的第二大值 list_test =[6,2,4,6,1,2,3,4,5] list_test.sort() print list_test[-2] "&q ...

  3. 计数排序与桶排序(bucket sort)

    Bucket Sort is a sorting method that subdivides the given data into various buckets depending on cer ...

  4. 数据结构杂谈(二)简单有趣的地精排序Gnome sort

    很早之前便听说过地精排序的名字,今天自己看来一下,发现这是一种非常简单而且有趣的排序算法. 为什么叫地精排序? 地精排序在2000年由Dr. Hamid Sarbazi-Azad 提出的时候被称作 s ...

  5. sort 树 hash 排序

    STL 中 sort 函数用法简介 做 ACM 题的时候,排序是一种经常要用到的操作.如果每次都自己写个冒泡之类的 O(n^2) 排序,不但程序容易超时,而且浪费宝贵的比赛时间,还很有可能写错. ST ...

  6. python 字典排序 关于sort()、reversed()、sorted()

    一.Python的排序 1.reversed() 这个很好理解,reversed英文意思就是:adj. 颠倒的:相反的:(判决等)撤销的 print list(reversed(['dream','a ...

  7. (C++)STL排序函数sort和qsort的用法与区别

    主要内容: 1.qsort的用法 2.sort的用法 3.qsort和sort的区别 qsort的用法: 原 型: void qsort(void *base, int nelem, int widt ...

  8. 排序命令sort

    Unix和Linux自带的sort命令功能非常强大,其主要功能是对文本内容按不同的方法排序.它不仅可以按一个或多个字段排序,还可以合并文件.使用sort处理一些较大的文件时,可能处理速度会比较慢,但却 ...

  9. C++排序函数sort/qsort使用

    问题描述:        C++排序函数sort/qsort的使用 问题解决:           (1)sort函数使用   注:           sort函数,参数1为数组首地址,参数2是数组 ...

随机推荐

  1. LeetCode 题解:Populating Next Right Pointers in Each Node I & II 二有难度。考虑不全面。

    每次应该把root同层的右侧节点传过来.如果没有,就传NULL. 同时,应该是先右后左. 感觉这次的代码还挺简洁的.. void construct(struct TreeLinkNode *root ...

  2. ubuntu交换Caps 和 ESC

    https://askubuntu.com/questions/363346/how-to-permanently-switch-caps-lock-and-esc This will allow y ...

  3. React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined.

    昨天在项目中,重新封装组件时,引用了原来的一个子组件,但发现子组件在其他页面正常,在新的组件里面就发生保存, 然后把子组件注释,随便显示其div元素也正常,纠结了很久,最后发现引用的方式有问题 子组件 ...

  4. 16.监听器-基础.md

    目录 概念 监听器功能 监听创建或销毁 监听属性变化 session相关监听 概念 实现特定接口的普通java类 *监听特定对象的创建.销毁或属性变化: 对象自己创建自己用:无需监听 对象别人创建自己 ...

  5. thread == 票池

    public class ThreadDemo2 { public static void main(String[] args){ TicketPool tp = new TicketPool(); ...

  6. 全局异常 同时ajax或是web跳转

    F8功能强大  在java代码debug的时候,F8键可直接跳到下一个类中.免去下一步 只用把之前两种方式合并即可,就是在exception包中不要ajax的异常,将其放入到web异常中,用if    ...

  7. Java 分页与原理(上)

    Java web 实习需要用到分页技术 所以现在学习一下 做个记录 方便以后查阅 分类:传统分页技术 下拉式分页技术 起始位置(0)开始 查询(10条记录)

  8. platform 系统是windows还是liunx

    import platform # 判断当前代码运行的系统是windows还是liunx print(platform.architecture()) print(platform.platform( ...

  9. Java中String的intern方法,javap&cfr.jar反编译,javap反编译后二进制指令代码详解,Java8常量池的位置

    一个例子 public class TestString{ public static void main(String[] args){ String a = "a"; Stri ...

  10. HashMap、LinkedHashMap、ConcurrentHashMap、ArrayList、LinkedList 底层实现

    HashMap相关问题 1.你用过HashMap吗?什么是HashMap?你为什么用到它? 用过,HashMap是基于哈希表的Map接口的非同步实现,它允许null键和null值,且HashMap依托 ...