В общем, вы хотите знать, существует ли какой-либо алгоритм сортировки, который не ухудшился бы по сравнению со средним регистром, если бы была дана функция сравнения, аналогичная:
int Compare(object a, object b) { return Random.Next(-1,1); }
... где Random.Next () - это некоторый метод, который будет генерировать случайно сгенерированное целое число между указанной включающей нижней и верхней границей.
Ответ на самом деле заключается в том, что большинство основных алгоритмов сортировки будут работать в соответствии со своим средним регистром, поскольку они подчиняются как минимум одному из следующих двух условий:
- Сравнение между двумя уникальными элементами никогда не выполняется дважды в сортировке и / или
- На каждой итерации сортировки определяется правильная позиция хотя бы одного элемента, поэтому этот элемент никогда не сравнивается снова.
Например, SelectionSort перебирает подсписок несортированных элементов, находит «наименьший» и / или «наибольший» элемент (сравнивая каждый из наибольших на данный момент), помещает его в правильную позицию и повторяет. В результате, даже с недетерминированным компаратором, в конце каждой итерации алгоритм найдет значение, которое он считает наименьшим или наибольшим, поменяет его на элемент в позиции, которую он пытается определить, и никогда не учитывает этот элемент снова, таким образом, он подчиняется условию 2. Тем не менее, A и B могут сравниваться несколько раз в течение этого процесса (в качестве самого крайнего примера рассмотрим несколько проходов SelectionSort для массива, отсортированного в обратном порядке), поэтому он нарушает условие 1 ,
MergeSort подчиняется условию 1, но не 2; поскольку подмассивы объединяются, элементы в одном и том же подмассиве (на левой или правой стороне) не сравниваются друг с другом, поскольку уже было определено, что элементы на этой стороне массива располагаются в порядке между собой; алгоритм сравнивает только наименее неотбираемый элемент каждого подмассива с другим, чтобы определить, какой из них меньше и должен идти следующим в объединенном списке. Это означает, что любые два уникальных объекта A и B будут сравниваться друг с другом не более одного раза, но «конечный» индекс любого данного элемента в полной коллекции не известен до тех пор, пока алгоритм не будет завершен.
InsertionSort подчиняется только условию 1, хотя его общая стратегия и сложность больше похожи на SelectionSort. Каждый несортированный элемент сравнивается с отсортированными элементами по возрастанию, пока не будет найден один элемент, который меньше проверяемого элемента. элемент вставляется в этот момент, а затем рассматривается следующий элемент. Результатом является то, что относительный порядок любых A и B определяется одним сравнением, и дальнейшие сравнения между этими A и B никогда не выполняются, но окончательное положение любого элемента не может быть известно, пока не будут рассмотрены все элементы.
QuickSort подчиняется обоимУсловия. На каждом уровне поворот выбирается и размещается таким образом, что «левая» сторона содержит элементы, меньшие, чем стержень, а «правая» сторона содержит элементы, превышающие стержень. Результатом этого уровня является QuickSort (слева) + pivot + QuickSort (справа), что в основном означает, что положение элемента pivot известно (на один индекс больше, чем длина левой стороны), pivot никогда не сравнивается с любым другим элементом. после того, как он был выбран в качестве точки поворота (его можно было сравнить с предыдущими элементами точки поворота, но эти элементы также известны и не включены ни в какие подрешетки), а любые А и В, которые заканчиваются на противоположных сторонах точки поворота, никогда не будут по сравнению. В большинстве реализаций чистой QuickSort базовый случай - это один элемент, в котором его текущий индекс является его конечным индексом, и дальнейшие сравнения не производятся.
Единственный сравнительный вид, о котором я могу подумать, что он не будет соответствовать ни одному из условий, - это неоптимизированная BubbleSort. Если сортировка не принимает, что наибольшие элементы X находятся на своем месте после выполнения проходов X, и / или использует проход «двойной проверки» для проверки сортировки списка, сортировка будет считаться «выполненной» только тогда, когда случайный компаратор возвратил -1 или 0 для каждых двух смежных элементов в списке во время прохода, и, таким образом, обмены не были выполнены (событие, которое, если оно действительно случайное, произойдет с вероятностью ; для сравнительно небольшого списка из 25 элементов это один шанс на 2000, в то время как для 100 элементов вероятность составляет 3,7 * 10 -18.(2/3)N−1). По мере того, как максимальное абсолютное значение результата компаратора увеличивается, вероятность того, что какое-либо одно сравнение вернет отрицательное значение или ноль, уменьшается в сторону 0,5, что значительно снижает вероятность завершения алгоритма (вероятность 99 монет переворачивает все посадочные головки). Это то, к чему все сводится, 1 к 1,2 * 10 30 )
РЕДАКТИРОВАНИЕ ПОСЛЕДНЕГО ВРЕМЕНИ: Есть несколько «сортов», разработанных специально как примеры того, что не нужно делать, которые включают случайный компаратор; пожалуй, самым известным является BogoSort. Msgstr "Если список не в порядке, перетасуйте список и проверьте снова". Теоретически это в конечном итоге приведет к правильной перестановке значений, точно так же как «неоптимизированная BubbleSort» выше, но средний случай - факториальное время (N! / 2), и из-за проблемы дня рождения (после достаточно случайных перестановок вы с большей вероятностью встречаются повторяющиеся перестановки, чем уникальные) существует ненулевая вероятность того, что алгоритм никогда не завершится официально, алгоритм не ограничен по времени.