簡體   English   中英

Array.Sort是如何在.NET中實現的?

[英]how was Array.Sort implemented in .NET?

我在編程中使用結構,並使用IComparer根據結構中的值對結構進行排序。

Microsoft如何實現Array.Sort()方法? 有沒有這方面的文件(參考)? 對於Visual Basic中的所有類型的Sort() ,它是否相同?

這是我想要的一個簡單的例子。

Dim MyArray(6) As Integer
    MyArray(0) = 1
    MyArray(1) = 45
    MyArray(2) = 45
   ' Some Code.....
    '.........
    '..........
    MyArray(3) = 1
    MyArray(4) = 10
    ' Some Code.....
    '.........
    '..........
    MyArray(5) = 1
    MyArray(6) = 57

    Array.Sort(MyArray)

Array.Sort()將此數組排序為: (1 1 1 10 45 45 57)

1號怎么排序? 它是將第一個結束還是保留在同一個索引中?

在我的原始示例中(排序之前), MyArray(0) = 1並且在排序MyArray(0) = 1

這是相同的原始1或另一個1(添加到陣列的最新的一個)移動到那個位置?

如果排序后MyArray(0) = 1 ,則排序前應為MyArray(5) = 1

它使用Quicksort算法,當有效實施(就地)時,該算法不穩定。 這意味着它不能保證相等的值在排序后保持其先前的相對位置。

例如,如果你有一堆點:

Point[] points = new Point[]
{
   new Point(0, 1),
   new Point(0, 2),
   new Point(0, 3),
   new Point(1, 1),
   new Point(1, 2),
   new Point(1, 3)
};

並且您使用此比較器按x坐標對這些點進行排序:

private int CompareByX(Point a, Point b)
{
    return a.X - b.X;
}

它只能保證點按x坐標排序,這意味着你可以很容易地得到一個混合順序(當看y坐標時):

Point(0, 3)
Point(0, 2)
Point(0, 1)
Point(1, 3)
Point(1, 2)
Point(1, 1)

[編輯]

這並不意味着排序算法是非確定性的(隨機的)。 對於相同的輸入數據,您將在每次運行時獲得相同的輸出數據。 如果精確檢查算法,也可以預測重組的實際方式,但這是不必要的。 只需知道在使用sort例程時就會發生這種情況就足夠了。

下面是您的問題的一個工作示例,嘗試更改測試數據大小( Main第一行)並觀察每次運行時如何重組數組:

class Program
{
    static void Main()
    {
        Point[] points = CreateTestData(1, 4).ToArray();
        DisplayItems("Before", points);
        Array.Sort(points, CompareByX);
        DisplayItems("After", points);
        Console.ReadLine();
    }

    private class Point
    {
        public int X { get; private set; }
        public int Y { get; private set; }
        public override string ToString()
        { return string.Format("({0},{1})", X, Y); }
        public Point(int x, int y)
        { X = x; Y = y; }
    }

    private static int CompareByX(Point a, Point b)
    { return a.X - b.X; }

    private static IEnumerable<Point> CreateTestData(int maxX, int maxY)
    {
        for (int x = 0; x <= 1; x++)
            for (int y = 0; y <= 4; y++)
                yield return new Point(x, y);
    }

    private static void DisplayItems(string msg, Point[] points)
    {
        Console.WriteLine(msg);
        foreach (Point p in points)
            Console.WriteLine(p.ToString());
        Console.WriteLine();
    }
}

當然,如果擴展比較器委托以包含Y坐標,則不會出現此問題:

    private static int CompareByX(Point a, Point b)
    {
         if (a.X == b.X) 
            return a.Y - b.Y;
         else
            return a.X - b.X;
    }

Array.Sort是一種不穩定的排序,因此相同元素的順序是未定義的而不是守恆的。 MSDN中有關Array.Sort的文章指出:

此方法使用QuickSort算法。 此實現執行不穩定的排序; 也就是說,如果兩個元素相等,則可能不會保留它們的順序。 相反,穩定的排序保留了相等元素的順序。

另一方面,LINQ的OrderBy方法是穩定的。 MSDN中關於OrderBy的文章指出:

該方法執行穩定的排序; 也就是說,如果兩個元素的鍵相等,則保留元素的順序。 相反,不穩定的排序不會保留具有相同鍵的元素的順序。

使用.Net Reflector並親自查看...從方法名稱看起來它們使用的是QuickSort算法:System.Array + SorterObjectArray.QuickSort

與大多數內置分類器一樣,Array.Sort()在幕后的助手類中使用QuickSort實現。 排序相對有效,可以使用IComparable和IComparer接口進行定制,但它不穩定; 您的示例中的三個1可能會以與排序之前不同的相對順序結束。 如果使用更復雜的結構,可以看到這個:

struct TestStruct
{
   int a;
   int b;
}

...

//As declared, this array is already sorted by both "a" and "b" properties
var myStructAray = new [] {new TestStruct{a=1,b=1}, new TestStruct{a=1,b=2}, new TestStruct{a=1,b=3});

//QuickSorts myStructArray based on the comparison of the lambda for each element
var newArray = Array.Sort(myStructArray, x=>x.a); 

//newArray may have a different order as myStructArray at this time
for(var i=0;i<myStructArray.Count();i++)
{
   //NUnit assertion; will almost surely fail given a sufficient array length
   Assert.AreEqual(myStructArray[i].b, newArray[i].b);
}

首先,讓我們解決當前計划中有關.Net(VB或C#)最佳實踐的幾個問題:

  1. 除非你有充分的理由不這樣做,否則選擇Class over Class
  2. 避免使用數組
  3. 您可以將該數組構建為單行: Dim MyArray() As Integer = {1, 45, 45, 1, 10, 1, 57}

至於你是否是“相同”值1的問題,答案是它取決於你如何看待它。 對於一般情況,答案是排序算法是否被認為是穩定的 .Net的排序算法不穩定。

對於這個特定情況,你問的是錯誤的問題。 1是1是1.它們之間沒有區別。 如果您覺得這很重要,我會挑戰您提供代碼來檢測原始代碼中該列表中任何兩個“1”之間的差異(除了數組索引)。

其他答案基於舊文檔,所以這是一個更新的答案。 根據最新文檔 (強調我的):

.NET Framework 4及更早版本使用Quicksort算法。 現在, Array.Sort使用內省排序(introsort)算法 ,如下所示:

  • 如果分區大小少於16個元素,則使用插入排序算法。

  • 如果分區數超過2 * Log N ,其中N是輸入數組的范圍,則它使用Heapsort算法。

  • 否則,它使用Quicksort算法。

它仍然是一種不穩定的類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM