c#: List.Sort()實現穩固排序(stable sort)

來源:互聯網
上載者:User

標籤:strong   tostring   work   add   結構   range   readline   png   tac   

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[] { "3", "2", "1", "4" });    list.Sort((x, y) =>    {        return 0;    });    foreach (string s in list)        Console.WriteLine(s);

其輸出為:

驗證上述結果,推測它是使用了二分法快速反序,把後半部分置前了。

可八輩的我們寧願它輸入為原始順序3214,這個合理,但是,可是,它無恥的變了……

 

3、實際情境

比如,我們需要對特定的對象進行排序,如下摘取網上例子稍加修正,以做樣本:

    static void Main(string[] args)    {        var p1 = new Person() { Name = "Abby", Age = 38 };        var p4 = new Person() { Name = "Jason", Age = 23 };        var p2 = new Person() { Name = "Bob", Age = 23 };        var p3 = new Person() { Name = "Charlie", Age = 23 };        var p5 = new Person() { Name = "Danielle", Age = 18 };        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 = 1;            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 = 1; if (obj != null && obj is Person) { var person = (Person)obj; result = this.Age.CompareTo(person.Age); if (result == 0) result = this.SortIndex.CompareTo(person.SortIndex); } return result; } ... }

初始化時,加入其索引:

        var p1 = new Person() { Name = "Abby", Age = 38, SortIndex = 0 };        var p4 = new Person() { Name = "Jason", Age = 23, SortIndex = 1 };        var p2 = new Person() { Name = "Bob", Age = 23, SortIndex = 2 };        var p3 = new Person() { Name = "Charlie", Age = 23, SortIndex = 3 };        var p5 = new Person() { Name = "Danielle", Age = 18, SortIndex = 4 };

輸出順序:

保留初始順序,解決問題。

 

後記:

之前未曾留意,此問題發現倒是很有意思,度娘不給力,解決問題還是要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)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.