代码之家  ›  专栏  ›  技术社区  ›  Pop Catalin

.NET的“array.sort()”方法使用的排序算法是稳定的算法吗?

  •  57
  • Pop Catalin  · 技术社区  · 16 年前

    是.NET使用的排序算法吗? Array.Sort() 方法A stable 算法?

    5 回复  |  直到 11 年前
        1
  •  65
  •   Rasmus Faber    11 年前

    MSDN :

    这个实现执行一个不稳定的排序;也就是说,如果两个元素相等,它们的顺序可能不会被保留。相反,一个稳定的排序保留了元素相等的顺序。

    这种类型使用反省类型。(在.NET Framework 4.0及更低版本中进行快速排序)。

    如果你需要一个稳定的种类,你可以使用 Enumerable.OrderBy .

        2
  •  64
  •   Community CDub    8 年前

    添加到 Rasmus Faber's answer 艾斯

    在LINQ中排序,通过 Enumerable.OrderBy Enumerable.ThenBy ,是一个稳定的排序实现,可以用作 Array.Sort . 从 Enumerable.OrderBy documentation over at MSDN :

    该方法执行稳定排序; 也就是说,如果两个元素的键 是相等的,元素的顺序 被保存下来。相反,不稳定 排序不保留 具有相同键的元素。

    此外,任何不稳定的排序实现,如 Array.Sort ,可以使用源序列或数组中元素的位置作为附加键来充当连接断路器来稳定。下面是一个这样的实现,作为任何一维数组上的一个通用扩展方法, 数组排序 变成一种稳定的类型:

    using System;
    using System.Collections.Generic;
    
    public static class ArrayExtensions {
    
        public static void StableSort<T>(this T[] values, Comparison<T> comparison) {
            var keys = new KeyValuePair<int, T>[values.Length];
            for (var i = 0; i < values.Length; i++)
                keys[i] = new KeyValuePair<int, T>(i, values[i]);
            Array.Sort(keys, values, new StabilizingComparer<T>(comparison));
        }
    
        private sealed class StabilizingComparer<T> : IComparer<KeyValuePair<int, T>> 
        {
            private readonly Comparison<T> _comparison;
    
            public StabilizingComparer(Comparison<T> comparison) {
                _comparison = comparison;
            }
    
            public int Compare(KeyValuePair<int, T> x, 
                               KeyValuePair<int, T> y) {
                var result = _comparison(x.Value, y.Value);
                return result != 0 ? result : x.Key.CompareTo(y.Key);
            }
        }
    }
    

    下面是一个使用 StableSort 自上而下:

    static class Program 
    {
        static void Main() 
        {
            var unsorted = new[] {
                new Person { BirthYear = 1948, Name = "Cat Stevens" },
                new Person { BirthYear = 1955, Name = "Kevin Costner" },
                new Person { BirthYear = 1952, Name = "Vladimir Putin" },
                new Person { BirthYear = 1955, Name = "Bill Gates" },
                new Person { BirthYear = 1948, Name = "Kathy Bates" },
                new Person { BirthYear = 1956, Name = "David Copperfield" },
                new Person { BirthYear = 1948, Name = "Jean Reno" },
            };
    
            Array.ForEach(unsorted, Console.WriteLine);
    
            Console.WriteLine();
            var unstable = (Person[]) unsorted.Clone();
            Array.Sort(unstable, (x, y) => x.BirthYear.CompareTo(y.BirthYear));
            Array.ForEach(unstable, Console.WriteLine);
    
            Console.WriteLine();
            var stable = (Person[]) unsorted.Clone();
            stable.StableSort((x, y) => x.BirthYear.CompareTo(y.BirthYear));
            Array.ForEach(stable, Console.WriteLine);
        }
    }
    
    sealed class Person 
    {
        public int BirthYear { get; set; }
        public string Name { get; set; }
    
        public override string ToString() {
            return string.Format(
                "{{ BirthYear = {0}, Name = {1} }}", 
                BirthYear, Name);
        }
    }
    

    下面是上面示例程序的输出(在安装了Windows Vista SP1和.NET Framework 3.5 SP1的计算机上运行):

    { BirthYear = 1948, Name = Cat Stevens }
    { BirthYear = 1955, Name = Kevin Costner }
    { BirthYear = 1952, Name = Vladimir Putin }
    { BirthYear = 1955, Name = Bill Gates }
    { BirthYear = 1948, Name = Kathy Bates }
    { BirthYear = 1956, Name = David Copperfield }
    { BirthYear = 1948, Name = Jean Reno }
    
    { BirthYear = 1948, Name = Jean Reno }
    { BirthYear = 1948, Name = Kathy Bates }
    { BirthYear = 1948, Name = Cat Stevens }
    { BirthYear = 1952, Name = Vladimir Putin }
    { BirthYear = 1955, Name = Bill Gates }
    { BirthYear = 1955, Name = Kevin Costner }
    { BirthYear = 1956, Name = David Copperfield }
    
    { BirthYear = 1948, Name = Cat Stevens }
    { BirthYear = 1948, Name = Kathy Bates }
    { BirthYear = 1948, Name = Jean Reno }
    { BirthYear = 1952, Name = Vladimir Putin }
    { BirthYear = 1955, Name = Kevin Costner }
    { BirthYear = 1955, Name = Bill Gates }
    { BirthYear = 1956, Name = David Copperfield }
    
        3
  •  20
  •   Jon Skeet    16 年前

    如其他答案所述,array.sort不稳定。但是,linq orderby方法(和orderbyDescending等) 稳定,非常有用。

        4
  •  3
  •   Konrad Rudolph    16 年前

    不,它 isn't :

    此方法使用快速排序算法。此实现执行不稳定排序

        5
  •  -3
  •   halority    12 年前

    更新: 此代码不稳定array.sort(确保元素始终按相同顺序排序):

    public static class ComparisonExtensions
    {
        public static Comparison<T> WithGetHashCode<T>(this Comparison<T> current)
        {
            return (x, y) =>
            {
                var result = current(x, y);
                if (result == 0)
                    return x.GetHashCode() - y.GetHashCode();
                return result;
            };
        }
    }
    

    用途:

    Comparison<Person> comparison = (x, y) => x.BirthYear.CompareTo(y.BirthYear);
    Array.Sort(unstable, comparison.WithGetHashCode());