как Array.Sort реализован в .NET? - PullRequest
4 голосов
/ 27 октября 2010

Я использую структуры в своем программировании и сортирую структуру по значению в структуре, используя IComparer.

Как Microsoft реализовала метод Array.Sort()? Есть ли какие-либо документы (ссылки) для этого? Это одинаково для всех типов Sort() в Visual Basic?

Это простой пример того, что я хочу.

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 до сортировки.

Ответы [ 5 ]

9 голосов
/ 27 октября 2010

Используется алгоритм 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)

[Edit]

Это не означает, что алгоритм сортировки недетерминирован (случайным образом).Для одинаковых входных данных вы будете получать одинаковые выходные данные при каждом запуске.Вы также можете предсказать фактическую реорганизацию, если точно изучите алгоритм, но это не нужно.Достаточно просто знать, что это происходит при использовании процедуры сортировки.

Вот рабочий пример вашей проблемы, попробуйте изменить размеры тестовых данных (первая строка в 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;
    }
7 голосов
/ 27 октября 2010

Array.Sort является нестабильной сортировкой, поэтому порядок одинаковых элементов не определен и не сохраняется.Статья о Array.Sort в MSDN гласит:

Этот метод использует алгоритм быстрой сортировки.Эта реализация выполняет нестабильную сортировку;то есть, если два элемента равны, их порядок может не сохраниться.Напротив, стабильная сортировка сохраняет порядок элементов, которые равны.

С другой стороны, методы LINQ OrderBy являются стабильными.Статья о OrderBy в MSDN гласит:

Этот метод выполняет устойчивую сортировку;то есть, если ключи двух элементов равны, порядок элементов сохраняется.Напротив, нестабильная сортировка не сохраняет порядок элементов с одинаковым ключом.

6 голосов
/ 27 октября 2010

Array.Sort (), как и большинство встроенных сортировщиков, использует реализацию QuickSort в классе помощника за кулисами. Сортировка является относительно эффективной и настраиваемой с использованием интерфейсов IComparable и IComparer, но она нестабильна; три единицы в вашем примере могут оказаться в другом относительном порядке, чем до сортировки. Вы можете увидеть это, если используете более сложную структуру:

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);
}
6 голосов
/ 27 октября 2010

Используйте .Net Reflector и убедитесь сами ... Из названий методов похоже, что они используют алгоритм быстрой сортировки: System.Array + SorterObjectArray.QuickSort

3 голосов
/ 27 октября 2010

Прежде всего, давайте рассмотрим несколько проблем в вашем текущем плане в отношении лучших практик для .Net (VB или C #):

  1. Предпочитайте класс над структурой, если у вас нет веских причин поступить иначе
  2. Избегайте использования массивов
  3. Вы можете построить этот массив как однострочный: Dim MyArray() As Integer = {1, 45, 45, 1, 10, 1, 57}

Что касается вашего вопроса о том, является ли это «тем же» значением 1, ответ таков: это зависит от того, как вы на это смотрите. В общем случае ответ заключается в том, считается ли алгоритм сортировки стабильным . Алгоритм сортировки .Net не стабильный.

В этом конкретном случае вы задаете не тот вопрос. 1 есть 1 есть 1. Между ними нет различия. Если вам кажется, что это имеет значение, я призываю вас предоставить код, чтобы обнаружить разницу между любыми двумя «1» из этого списка в исходном коде (кроме индекса массива).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...