Быстрая сортировка слиянием

Missi4ka

Якобы сабж позволяет всегда обеспечивать сложность n log n в отличии от обычной quicksort делением, где трудоемкость в "плохих" случаях порядка n^2.
Поясните на пальцах алгоритм, плиз, или подскажите инфу по сабжу.

lurgi48

На пальцах:
Идея :сортировать массив из двух элементов очень просто и быстро.
1. Разбиваем массив на пары и сортируем в них
2. Соединяем пары в четверки. (Алгоритм построения из двух упорядоченных массивов третьего тривиален. Просто сравниваем элементы и нужные добавляем)
3. Соединяем четверки в восьмерки и тд
Памяти: еще один массив такой же длины (на каждом шаге либо из первого во второй записывать либо из второго в первый)
Память нужна обязательно, тк иначе алгоритм слияния двух отсортированных массивов не построить.

Missi4ka

Прости за тормозню, что-то не очень очевидно, как строить упорядоченный массив из двух упорядоченных. Это ведь надо делать за n операций...

lurgi48

насколько помню. есть три указателя (номера элементов как бы первых) по массивам. Два на исходные. Один на результирующий.
Сравниваем элементы соответствующие двум указателям и больший (меньший) записываем на место
куда указывает третий указатель. сдвигаем что надо и дальше. Когда один из массивов закончиться второй
просто дописывам
ЗЫ: насколько помню там только операции сравнения считаются. Их как раз сумма длин исходных будет

Missi4ka

Напрмер, если есть два массива 1,3,5,7,9 и 2,4,6,8,10, то слияние займет 5 операций. Это худьший случай для массивов длины 5, да?

lurgi48

Да

Missi4ka

Санькс.

a10063

Напрмер, если есть два массива 1,3,5,7,9 и 2,4,6,8,10, то слияние займет 5 операций.
не 5, а 10
сумма длин...

Missi4ka

Сорри, ступил.

bleyman

Однако в среднем квиксорт делает сортировку слиянием за счёт значительно меньшей константы.

bastii

А какой алгоритм хорош для "досортировки", когда обычно в целом элементы упорядочены, но локально есть небольшие отклонения, т.е. число элементов не на своих местах много меньше общего числа элементов.
Также интересует случай, когда число элементов не очень большое, например, меньше 100. Для какого существует наиболее эффективная реализация с точки зрения операций с памятью, но т.е. реально на практике.

Missi4ka

Пузырёк! Если в массиве мало инверсий, скажем m, а всего элементов n, то трудоемкость будет порядка m n.

bleyman

Кстати стандартный С-шный qsort использует пузырёк для коротких массивов (порядка 8 элементов).
Вообще есть мега-метод: если не уверен, что qsort не начнёт вдруг тормозить на твоих данных, можно за линейно время их рандомно перемешать и потом сортировать =)

lurgi48

хммм. когда я читал про слияние и qsort, то там сложности были nlogn и Cnlogn, где C скажем так в среднем где-то порядка 6. Что явно хреновее, чем слияние.
In the worst case, merge sort does about 39% fewer comparisons than quicksort does in the average case; merge sort always makes fewer comparisons than quicksort, except in extremely rare cases, when they tie, where merge sort's worst case is found simultaneously with quicksort's best case. In terms of moves, merge sort's worst case complexity is O(n log n)—the same complexity as quicksort's best case, and merge sort's best case takes about half as many iterations as the worst case.

Missi4ka

если достаточно памяти, помнится, можно использовать сортировку вставкой (ни разу не писал у нее линейная трудоемкость

Dasar

напомню, что сложность сортировки определяется не только кол-вом сравнений, но и:
1. кол-вом присваиваний
2. кол-вом дополнительной памяти
например, у слияния - очень высокое кол-во присваиваний (n^2) и доп. память порядка n элементов

Missi4ka

насчёт присваиваний, может и соглашусь. А вот память --- это, простите, другой показатель. Не трудоёмкость уже.

Dasar

> Не трудоёмкость уже
да хоть горшком назови...
т.е. можно поспорить, как это назвать и куда отнести...
но главное, что факт остается фактом - что разные алгоритмы требуют разный объем доп. памяти, соответственно при сортировке больших массивов требования к наличию доп. памяти - могут быть довольно накладными.

bleyman

если достаточно памяти, помнится, можно использовать сортировку вставкой (ни разу не писал у нее линейная трудоемкость
Сортировки быстрее чем за nlogn (в худшем случае, с произвольными данными и стандартной операцией сравнения) не бывает, что несложно доказать, только я не помню, как именно =(

Helga87

через количество перестановок это доказывается

yroslavasako

если достаточно памяти, помнится, можно использовать сортировку вставкой (ни разу не писал у нее линейная трудоемкость
у сортировки вставкой трудоемкость квадратичная. Вы еще забыли сортировку подсчетом
O(n+m) n - чилос элементов массиова, m - число различных значений, которые может принимать элемент массиова. Памяти ей надо O(m).

Marinavo_0507

> у слияния - очень высокое кол-во присваиваний (n^2)
бред
> и доп. память порядка n элементов
не обязательно

Ivan8209

> Сортировки быстрее чем за nlogn (...) не бывает
Наглая ложь.
---
...Я работаю антинаучным аферистом...

bleyman

Наглая ложь.
Да, если заменить "(в худшем случае, с произвольными данными и стандартной операцией сравнения)" на "(...)", то получится наглая ложь. Именно поэтому в моём комментарии написано "(в худшем случае, с произвольными данными и стандартной операцией сравнения)", а не "(...)".

Missi4ka

Да, возможно ты и прав. Я только помню, что при некоторых ограничениях на массив возможна сортировка за O(n). Только не помню, какие это были ограничения. Кажется, все элементы массива должеы принадлежать множеству значений с известным (небольшим) числом элементов.
Вообще, надо кафедральные мехматовские методички по этому поводу посмотреть. Валединский и компания.

Missi4ka

Количество памяти -- это другой из двух важнейших параметров алгоритма наряду с трудоёмкостью. Обычно количество памяти и трудоемкость обратно пропорциональны (грубо говоря). поэтому в зависимости от ситуации берут тот или другой алгоритм.

bastii

Ну да, можно просто сосчитать вхождения каждого значения. Только тогда нужно еще задуматься, а нужен ли такой отсортированный массив, мб лучше как-то по другому хранить, например, как упорядоченную последовательность значение + число элементов <= этому значению.

lurgi48

Кажется, все элементы массива должеы принадлежать множеству значений с известным (небольшим) числом элементов.
Именно так. Тогда можно за O(n) отсортировать

Ivan8209

За линейное время можно сортировать и большие текстовые таблицы.
---
...Я работаю антинаучным аферистом...

Dasar

> бред
согласен, тормознул
присваиваний - n * log n
>> и доп. память порядка n элементов
> не обязательно
приведи пример реализации

Marinavo_0507

типа если мы сортируем не настоящие массивы, а списки, то можно обойтись константной памятью: элементы просто будут кочевать из списка в список
в общем, зависит от языка и от машины (м.б. виртуальной)
при использовании языка с GC вроде как преимуществ у qsort я не вижу

Dasar

> типа если мы сортируем не настоящие массивы, а списки, то можно обойтись константной памятью: элементы просто будут кочевать из списка в список
как бы да, только список по сравнению с массивом - как раз и использует память порядка n.
> при использовании языка с GC вроде как преимуществ у qsort я не вижу
GC как раз не любит списки, поэтому в системах с GC "массивные" структуры данных и соотственно алгоритмы, которые используют эти "массивные" структуры предпочтительнее, чем списочные структуры данных

Marinavo_0507

> как бы да, только список по сравнению с массивом - как раз и использует память порядка n
виртуальные машины тоже добавляют оверхед такой - на боксы всякие и теги
а также MMU в процессоре
> GC как раз не любит списки
смотря какой и в каких задачах
например, если у нас много таких массивов разной длины, то искать для них непрерывные куски памяти может быть напряжно, в то время как выделять память под маленькие элементы любой нормальный аллокатор умеет очень эффективно

Dasar

> виртуальные машины тоже добавляют оверхед такой - на боксы всякие и теги
наверное, да, а может и нет.
я только не понял - как из этого следует, что слияние на списках не требует на O(n) памяти больше, чем qsort на массиве.
> например, если у нас много таких массивов разной длины, то искать для них непрерывные куски памяти может быть напряжно
так именно поэтому часто используют структуры данных в виде - ArrayList-ов (список массивов)

Marinavo_0507

> я только не понял - как из этого следует, что слияние на списках не требует
> на O(n) памяти больше, чем qsort на массиве
а нельзя это сравнивать, если разные машины
типа если писать на С в условиях фиксированной памяти, то qsort лучше
если на Lisp списки сортировать, то merge наверняка будет эффективнее, так как там VM заточена под выделение и освобождение cons

bastii

Плюс еще нужно помнить, что в варианте со списком +12 байт (а то и все +16 байт) на элемент по сравнению с массивом. Придется извращаться со списком в массиве.

bastii

Такой вопрос. У меня на практике часто возникает необходимость сортировать массивы. Но длина в них ограничена, т.е. можно завести дополнительный массив для использования при сортировке слиянием, и при необходимости, если сортируемый массив больше дополнительного массива, его увеличивать. Будет ли такой вариант лучше qsort? А если у меня к тому же операция сравнения сложная?

mira-bella

Однако в среднем квиксорт делает сортировку слиянием за счёт значительно меньшей константы.
AFAIK в среднем quicksort имеет ту же асимптотику n*ln(n но в худшем случае квадратичен
а вот merge_sort, heap_sort (который в отличие от merge_sort не требует дополнительной памяти) в худшем случае имеют асимптотику n*ln(n но в среднем хуже коэффициент чем у quicksort
Оставить комментарий
Имя или ник:
Комментарий: