В методе List‹T›.Sort() элемент когда-либо сравнивается сам с собой?

Если я передам пользовательский IComparer экземпляру метода Sort() списка, будет ли когда-либо вызываться метод компаратора Compare(x,y) с одним и тем же элементом?

т.е. Возможно ли, что Compare(x,x) может быть вызван.

Изменить: больше интересует случай, когда элементы списка различны.


person ForeverLearnNeverMaster    schedule 10.09.2011    source источник
comment
Конечно, если список‹› содержит один и тот же объект более одного раза.   -  person Hans Passant    schedule 10.09.2011
comment
@Hans: Да, немного запутался в моем удаленном комментарии. Я работал со списком, содержащим экземпляры класса. Конечно, в некоторых программах один и тот же экземпляр может встречаться в списке несколько раз. Но после редактирования мне был интересен случай, когда список содержал отдельные экземпляры класса.   -  person ForeverLearnNeverMaster    schedule 10.09.2011
comment
Я исправляюсь. Комментарий в справочном источнике гласит: предварительно отсортируйте низкие, средние (основные) и высокие значения на месте. Это повышает производительность при работе с уже отсортированными данными или данными, состоящими из нескольких отсортированных запусков, объединенных вместе.   -  person Hans Passant    schedule 10.09.2011
comment
Возможно это или нет, вы должны поддерживать это, потому что это часть контракта для функции сравнения.   -  person Raymond Chen    schedule 11.09.2011


Ответы (4)


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

using System;
using System.Collections.Generic;

static class Program
{
    class MyComparer : Comparer<int>
    {
        public override int Compare(int x, int y)
        {
            Console.WriteLine("Compare(" + x + ", " + y + ")");
            if (x < y) return -1;
            if (x > y) return 1;
            return 0;
        }
    }

    static void Main()
    {
        MyComparer comparer = new MyComparer();
        List<int> list = new List<int> { 1, 2, 3 };
        list.Sort(comparer);
        return;

    }
}

И вывод:

Compare(1, 2)
Compare(1, 3)
Compare(2, 3)
Compare(1, 2)
Compare(2, 2)
Compare(2, 3)
Compare(2, 2)
person JohnD    schedule 10.09.2011
comment
Хм, да. Добавлен Console.WriteLine() в начале метода Compare(). Compare(2,2) вызывается дважды для данного списка. - person ForeverLearnNeverMaster; 10.09.2011
comment
Подтверждено с помощью Mono 2.6.7.0. (Я позволил себе добавить директивы using и оператор WriteLine, чтобы людям было проще попробовать самостоятельно.) - person Thomas; 11.09.2011
comment
Этого больше не происходит (код С# идентичен вашему выше) с .NET 4.6.2. Сейчас пишет просто: Compare(1, 2) Compare(1, 3) Compare(2, 3) Эффективный. - person Jeppe Stig Nielsen; 29.08.2017

Из документов:

Этот метод использует Array.Sort, который использует алгоритм QuickSort.

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

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

person Thomas    schedule 10.09.2011
comment
Как это объясняет ответ JohnD? Я упускаю что-то очевидное? - person ForeverLearnNeverMaster; 10.09.2011
comment
За этот ответ продолжают голосовать все больше и больше v__v. Может ли кто-нибудь подтвердить указанное здесь поведение быстрой сортировки, которое, кажется, противоречит образцу программы JohnD? - person ForeverLearnNeverMaster; 10.09.2011
comment
Хм, это интересно! Я рад, что оба ответа появляются вверху, теперь, когда JohnD был принят. В этом случае мы должны сделать вывод, что документы неверны. - person Thomas; 11.09.2011
comment
Существует множество реализаций QuickSort, некоторые из которых сравнивают элементы против себя. В документах нет ничего плохого. - person Raymond Chen; 11.09.2011
comment
Я исправляюсь - я никогда не видел, чтобы QuickSort писался таким образом. Тем не менее, я утверждаю, что документы ошибаются, называя эту деталь реализации частью спецификации, а это не так. В качестве функции сортировки можно использовать любой квадратичный алгоритм наихудшего случая и алгоритм среднего случая nlogn. - person Thomas; 11.09.2011

Другой ответ, основанный на части XML ECMA-335, спецификация BCL (библиотека базовых классов). Хотя это не гарантирует связи с тем, что делают фактические реализации, это настолько авторитетно, насколько это возможно. И спецификация не говорит ничего, кроме:

В худшем случае эта операция выполняется за O(n^2), где n — количество элементов для сортировки. В среднем это O (n log n).

Хотя это наводит на мысль о QuickSort, это абсолютно не гарантирует. Спецификация также не требует реализации с точки зрения Array.Sort.

Итог: что касается спецификации, для реализации совершенно нормально сравнивать элементы с самими собой.

person Thomas    schedule 11.09.2011

Хотя это не является строго гарантированным, я почти уверен, что метод List Sort никогда не вызовет ваш метод сравнения для сравнения объекта с самим собой, если только этот объект не появится в списке несколько раз. Я основываю этот вывод на том, что List.Sort реализован с использованием алгоритма QuickSort (согласно MSDN), который никогда не сравнивает обычно не предполагает сравнения одного и того же элемента с самим собой (и ни один из других задокументированных алгоритмов сортировки, о которых я могу думать). (Редактировать: кажется, что реализация Microsoft действительно сравнивает элемент с самим собой. См. Принятый ответ выше.)

Однако в соответствии с хорошей практикой кодирования ваша реализация IComparer должна иметь возможность обрабатывать передачу одного и того же объекта в обоих параметрах, поскольку в противном случае ваша реализация не выполняет контракт, определенный IComparer. Это, вероятно, сработает для вашего сценария, но вы будете полагаться на детали реализации метода сортировки (которые могут измениться в будущем), и вы не сможете использовать свою реализацию IComparer в других сценариях, где такого нет. гарантия (или, что еще хуже, вы или кто-то другой ДЕЙСТВИТЕЛЬНО используете его и, возможно, создает трудно обнаруживаемую ошибку).

person Nimrand    schedule 10.09.2011