Чому сортування Radix не використовується частіше?


31

Він стабільний і має часову складність O (n). Це повинно бути швидшим, ніж такі алгоритми, як Quicksort і Mergesort, але я навряд чи коли-небудь бачу його використовувати.


2
Дивіться тут: en.wikipedia.org/wiki/Radix_sort#Efficiency Ефективність становить O (kn), і вона може бути не краща, ніж O (n * log (n)).
FrustratedWithFormsDesigner

2
Сорт Radix часто використовується в м'яких системах реального часу, таких як ігри. Переважає чи не один алгоритм інший, як завжди, залежить від усіх параметрів проблеми, а не лише від обмеженої складності
awdz9nld

@FrustratedWithFormsDesigner Можливо, вікі змінилася? Я більше не бачу посилання на `n log (n) , FWIW ...
rogerdpack

У Boost є (у варіанті місце) цього: boost.org/doc/libs/1_62_0/libs/sort/doc/html/sort/sort_hpp.html але так, я думаю, люди просто не знають, що існує ... або це, або всі вони просто використовують "стандартний" алгоритм сортування, який з будь-якої причини розробники рамок як і раніше використовують повторно "загальні" сорти, які не настільки ефективні ... можливо, вони не зосереджені на сортуванні вкладених як правило, оскільки це рідкісний випадок використання?
rogerdpack

Відповіді:


38

На відміну від сортування radix, quicksort є універсальним, тоді як сортування radix корисне лише для цілочисленних клавіш довжини виправлення.

Також ви повинні розуміти, що O (f (n)) дійсно означає в порядку K * f (n), де K - деяка довільна константа. Для radix сортування цей K виявляється досить великим (принаймні порядок кількості бітів у цілих числах відсортованих), з іншого боку, quicksort має один з найнижчих K серед усіх алгоритмів сортування та середню складність n * log (n). Таким чином, у реальному житті сценарій швидкосполучення буде дуже швидким, ніж радіаційний сорт.


Зауважте про зазначену складність: хоча (LSD) сорт Radix має складність O (n * K), ця константа зазвичай невелика, зазвичай вибирається така, що (2 ^ (W / K)) * C вписується в L1, де C - розмір у байтах лічильника, W розмір сортованого ключа. Більшість реалізацій вибирають K = [3,4] для 32-бітних слів на x86. K може також бути адаптованим до використання тимчасової когерентності (близької сортованості), оскільки кожен радіус сортується індивідуально.
awdz9nld

11
Примітка про універсальність: сорт Radix цілком здатний працювати з клавішами з плаваючою комою, а також цілими клавішами змінної довжини
awdz9nld

20

Більшість алгоритмів сортування мають загальне призначення. Враховуючи функцію порівняння, вони працюють над чим завгодно, і такі алгоритми, як Quicksort і Heapsort, будуть сортувати з додатковою пам'яттю O (1).

Сортування Radix є більш спеціалізованим. Вам потрібен певний ключ, який знаходиться в лексикографічному порядку. Вам потрібно одне відро для кожного можливого символу в ключі, а у відрах потрібно зберігати багато записів. (Крім того, вам потрібен один великий масив відер, який вміщатиме всі можливі ключові значення.) Ви, мабуть, потребуватимете значно більше пам’яті, щоб зробити радіаційне сортування, і ви будете використовувати його випадковим чином. Жодне з цього не добре для сучасних комп’ютерів, оскільки ви, ймовірно, отримаєте помилки сторінки, як-от Quicksort, отримають пропуски кешу.

Нарешті, люди взагалі більше не пишуть власні алгоритми сортування. Більшість мов мають бібліотечні засоби для сортування, і правильне, як правило, це використовувати. Оскільки radix сортування не є загальноприйнятним, воно, як правило, має бути адаптоване до фактичного використання та використовує багато додаткової пам’яті, важко ввести його у бібліотечну функцію чи шаблон.


Власне, quicksort вимагає O(n^2)пам'яті в гіршому випадку через nрекурсивні дзвінки на лівій і правій секціях. Якщо в реалізації використовується оптимізація хвостової рекурсії, її можна знизити до O(n)тих пір, оскільки виклики до потрібного розділу не потребують додаткового місця. ( en.wikipedia.org/wiki/Quicksort#Space_complexity )
Осколок хаосу

Потрібно лише S(n) \in O(n)місце для сортування за допомогою radix, тобто таке, як для купи або швидкого сортування.
Велда

@SplinterofChaos може змінитись вікі? Це, здається, вже не згадується n^2про quicksort, але O(log n)...
rogerdpack

Я не думаю, що це "набагато" більше пам'яті, можливо, 2 * n (гаразд, це набагато більше, але, можливо, не неможливо)? А відра настільки малі (якщо припустити, що ви розбиваєтеся на байти і повторюєтесь), що це може добре вписатися в кеш?
rogerdpack

5

Досить рідко буває, що ключі, за якими ви сортуєтесь, - це фактично цілі числа у відомому, рідкому діапазоні. Зазвичай у вас є літерні поля, які виглядають , як вони будуть підтримувати несравнітельное сортування, але так як реальні строки не розподілені рівномірно за алфавітом, це не працюють , як і повинно бути в теорії.

В іншому випадку критерій визначається лише оперативно (з урахуванням двох записів, ви можете вирішити, який на першому місці, але ви не можете оцінити, наскільки "далеко" внизу шкали є ізольований запис). Тому метод часто не застосовується, менш застосовний, ніж ви можете вважати, або просто не швидший, ніж O (n * log (n)).


Сортування Radix може обробляти цілі числа (або рядки) в будь-якому діапазоні, рекурсивно сортуючи їх "байт за один раз", щоб вони не мали бути в розрідженому діапазоні FWIW ...
rogerdpack

4

Я використовую його весь час, насправді більше, ніж порівняння на основі порівнянь, але я, правда кажучи, дивна куля, яка працює більше з числами, ніж будь-що інше (я ледь коли-небудь працюю зі струнами, і вони, як правило, інтерновані, якщо так, то в який момент радіакс сортування може бути знову корисним для фільтрації дублікатів та обчислення набірних перетинів; я практично ніколи не роблю лексикографічних порівнянь).

Основний приклад - радіаційне сортування точок за заданим виміром як частина пошуку або середній розкол або швидкий спосіб виявлення збіг точок, фрагментів сортування по глибині або радіаційне сортування масиву індексів, що використовуються в декількох петлях, щоб забезпечити більш зручний доступ до кешу шаблони (не повертаючись назад і назад лише в пам'яті, щоб повернутися знову і перезавантажити ту саму пам'ять у кеш-рядок). Принаймні в моєму домені (комп’ютерна графіка) є дуже широке застосування лише для сортування по 32-бітних та 64-бітних цифрових клавішах фіксованого розміру.

Я хотів би зафіксувати і сказати, що радіо-сортування може працювати на числа з плаваючою комою та мінуси, хоча складно написати версію FP, яка є максимально портативною. Крім того, хоча це O (n * K), K просто має бути кількістю байтів ключового розміру (наприклад: мільйон 32-бітових цілих чисел, як правило, займає 4 пропускні розміри в байтах, якщо у відрі є 2 ^ 8 записів ). Шаблон доступу до пам'яті також, як правило, набагато більш сприятливий для кешу, ніж quicksorts, хоча для цього потрібен паралельний масив і невеликий масив відра (другий, як правило, може добре розміщуватися на стеку). QS може зробити 50 мільйонів свопів для сортування масиву з мільйона цілих чисел із спорадичними шаблонами випадкового доступу. Сортування radix може це зробити за 4 лінійних, кешованих проходів над даними.

Однак, недостатня обізнаність про те, що можна зробити це за допомогою малого К, за від’ємними числами разом із плаваючою комою, може дуже суттєво сприяти відсутності популярності радіо-сортів.

Що стосується моєї думки щодо того, чому люди не користуються цим частіше, це може мати відношення до багатьох доменів, які, як правило, не мають потреби сортувати номери або використовувати їх як ключові слова пошуку. Однак, виходячи з мого особистого досвіду, багато моїх колишніх колег також не використовували його у випадках, коли це було ідеально підходить, і частково тому, що вони не усвідомлювали, що це може бути зроблено для роботи над ПП та негативів. Тож окрім того, що він працює лише на числових типах, часто вважається, що він є менш загальноприйнятим, ніж є насправді. Я б не використовував для нього майже такого ж використання, якби я вважав, що він не працює на числа з плаваючою комою та від'ємні цілі числа.

Деякі орієнтири:

Sorting 10000000 elements 3 times...

mt_sort_int: {0.135 secs}
-- small result: [ 12 17 17 22 52 55 67 73 75 87 ]

mt_radix_sort: {0.228 secs}
-- small result: [ 12 17 17 22 52 55 67 73 75 87 ]

std::sort: {1.697 secs}
-- small result: [ 12 17 17 22 52 55 67 73 75 87 ]

qsort: {2.610 secs}
-- small result: [ 12 17 17 22 52 55 67 73 75 87 ]

І це лише з моїм наївним реалізацією ( mt_sort_intтакож сортування радіацією, але з більш швидкою гілкою коду, враховуючи, що він може вважати, що ключ є цілим числом). Уявіть, наскільки швидкою може бути стандартна реалізація, написана експертами.

Єдиний випадок, коли я виявив, що сортування radix походить гірше, ніж на основі дійсно швидкого порівняння C ++, - std::sortце дійсно невелика кількість елементів, скажімо, 32, і тоді я вважаю, що std::sortпочинає використовувати сорти, які краще підходять для найменшої кількості елементів, наприклад, купелів або сортування вставки, хоча в цей момент моя реалізація просто використовує std::sort.


1
Завжди приємно чути думки людей, які мають досвід роботи в цій місцевості.
Френк Хілеман

З'являється mt_ - це багатопотокові реалізації: softwareengineering.stackexchange.com/a/362097/65606
rogerdpack

1

Ще одна причина: в наші дні сортування зазвичай реалізується за допомогою користувальницької процедури сортування, що додається до логіки сортування, що постачається компілятором. З радіальним сортуванням це було б значно складніше і стає ще гіршим, коли функція сортування діє на кілька клавіш змінної довжини. (Скажіть, ім'я та дату народження.)

У реальному світі я один раз реалізував радіаційний сорт. Це було в старі часи, коли пам’ять була обмежена, я не міг одразу привести всі свої дані в пам’ять. Це означало, що кількість доступу до даних набагато важливіше, ніж O (n) vs O (n log n). Я зробив один прохід через дані, розподіляючи кожен запис у відро (за списком яких записів, в яких бункерах, насправді нічого не переміщуючи). Для кожного непустого біна (мій ключ сортування був текст, було б багато порожні бункери) Я перевірив, чи можу я насправді занести дані в пам'ять - якщо так, введіть їх і використовуйте quicksort. Якщо ні, побудуйте тимчасовий файл, що містить лише елементи в bin, і викличте процедуру рекурсивно. (На практиці декілька бункерів переповнюватимуться.) Це спричинило два повних зчитування та одне повне записування до мережевого сховища і щось на зразок 10% від цього до локального сховища.

В наші дні такі проблеми з великими даними набагато важче зіткнутися, я, мабуть, ніколи більше нічого такого не напишу. (Якщо я зіткнувся з тими ж даними в ці дні, я б просто вказав 64-бітну ОС, додайте оперативну пам'ять, якщо ви потрапите в цей редактор.)


Захоплюючим врахуванням одного з недоліків, про який згадується іноді радіаційний сорт, є "це займає більше місця". Ще намагаюся обернути голову навколо цього ...
rogerdpack

1
@rogerdpack Це не те, що мій підхід використовував менше місця, це те, що він використовував менший доступ до даних. Я сортував файл, який знаходився біля гігабайт, працюючи з обмеженням компілятора (це був захищений DOS режим, а не Windows) трохи менше 16 Мб загального використання пам’яті, включаючи код та обмеження структури 64 кбіт.
Лорен Печтел

-1

Якщо всі ваші параметри - цілі числа, і якщо у вас більше 1024 вхідних параметрів, то сортування радіації завжди швидше.

Чому?

Complexity of radix sort = max number of digits x number of input parameters.

Complexity of quick sort = log(number of input parameters) x   number of input parameters

Отже, сортування радіоактивів швидше, коли

log(n)> max num of digits

Максимальне ціле число в Java - 2147483647. Що становить 10 цифр

Тож радіаційна сортування завжди швидша, коли

log(n)> 10

Тому сортування радікса завжди швидше, коли n>1024


У деталях реалізації є приховані константи, але в основному ви говорите "для більшого вхідного радіаційного сортування швидше", що ... повинно бути так! Просто важко знайти випадки використання для цього, але коли зможете ...
rogerdpack
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.