Який алгоритм сортування найкраще працює в основному відсортованих даних?
Який алгоритм сортування найкраще працює в основному відсортованих даних?
Відповіді:
На основі високонаукового методу перегляду анімованих gif-файлів я б сказав, що "Insertion" і "Bubble" - хороші кандидати.
Лише кілька предметів => ВСТАНОВЛЕННЯ СОРТ
Елементи в основному сортуються вже => ВСТУП СОРТ
Стурбовано найгіршими сценаріями => HEAP SORT
Цікавить хороший середній випадок => ШВИДКО
Предмети витягнуті з щільного Всесвіту => BUCKET SORT
Бажання написати якомога менше коду => ВСТАНОВИТИЙ СОРТ
Timsort - це "адаптивний, стабільний, природний злиття" з " надприродними показниками на багатьох видах частково впорядкованих масивів (менше, ніж lg (N!) Зіставлень, необхідних і не менше N-1)". Вбудований Pythonsort()використовує цей алгоритм деякий час, очевидно, з хорошими результатами. Він спеціально розроблений для виявлення та переваги частково відсортованих послідовностей на вході, які часто трапляються в реальних наборах даних. У реальному світі часто трапляється так, що порівняння набагато дорожчі, ніж обмін предметами в списку, оскільки, як правило, просто поміняють покажчики, що дуже часто робить тимчасовий вибір прекрасним вибором. Однак, якщо ви знаєте, що ваші порівняння завжди дуже дешеві (наприклад, написання іграшкової програми для сортування 32-бітових цілих чисел), існують інші алгоритми, які, ймовірно, можуть працювати краще. Найпростіший спосіб скористатись тимчасовим стилем - це, звичайно, використовувати Python, але оскільки Python є відкритим кодом, ви також можете отримати позичальний код. Крім того, вищеописаний опис містить більш ніж достатньо деталей, щоб написати власну реалізацію.
lg(n!)порівнянь на майже відсортованому масиві, аж до O(n)! | @behrooz: Ні порівняння сортування може мати середній випадок краще O(n log n), і lg(n!)це O(n log n). Тож найгірший випадок Timsort - асимптотично не гірший, ніж у будь-якого іншого порівняння. Крім того, його найкращий випадок кращий або рівний будь-якому іншому порівнянню.
Сортування вставки з такою поведінкою:
kв слотах 1..nспочатку перевірте, чи немає el[k] >= el[k-1]. Якщо так, перейдіть до наступного елемента. (Очевидно, пропустити перший елемент.)1..k-1щоб визначити місце вставки, а потім продемонструйте елементи. (Ви можете зробити це лише у тому випадку, k>Tколи де Tє порогове значення; при малому kце надмірність.)Цей метод дає найменшу кількість порівнянь.
Спробуйте інтроспективне сортування. http://en.wikipedia.org/wiki/Introsort
Це засновано на кікспортах, але це дозволяє уникнути найгіршого випадку поведінки, яке має кікспорт для майже відсортованих списків.
Хитрість полягає в тому, що цей алгоритм сортування виявляє випадки, коли швидкий вибір переходить у найгірший режим і переходить на групу чи злиття. Близько відсортовані розділи виявляються деяким не наївним методом розділів, а малі розділи обробляються за допомогою вставки.
Ви отримуєте найкраще з усіх основних алгоритмів сортування за вартістю коду та складності. І ви можете бути впевнені, що ви ніколи не зіткнетеся з найгіршим випадком поведінки незалежно від того, як виглядають ваші дані.
Якщо ви програміст на C ++, перевірте алгоритм std :: sort. Він може вже використовувати внутрішньоперспективний сортування внутрішньо.
Splaysort - незрозумілий метод сортування, заснований на хитрі дерева , тип адаптивного бінарного дерева. Splaysort хороший не лише для частково відсортованих даних, але й для частково зворотно-відсортованих даних, або взагалі будь-яких даних, що мають будь-який тип попереднього порядку. Це O (nlogn) у загальному випадку та O (n) у випадку, коли дані певним чином сортуються (вперед, назад, орган-труба тощо).
Його велика перевага перед сортуванням вставки полягає в тому, що він не повертається до поведінки O (n ^ 2), коли дані взагалі не сортуються, тому вам не потрібно бути абсолютно впевненим, що дані частково сортуються перед їх використанням .
Його недоліком є додатковий простір, який потребує структура дерева гри, яка йому потрібна, а також час, необхідний для створення та знищення дерева гри. Але залежно від розміру даних та кількості попередньої сортованості, яку ви очікуєте, накладні витрати можуть коштувати цього для збільшення швидкості.
Документ про splaysort був опублікований в Software - Practice & Experience.
вставка або сортування оболонки!
Гладкий сорт Dijkstra - це чудовий сорт для вже відсортованих даних. Це важкий варіант, який працює в O (n lg n) в гіршому випадку і в O (n) кращому випадку. Я написав аналіз алгоритму, на випадок, якщо вам цікаво, як він працює.
Природний злиття - це ще один дійсно хороший для цього варіант - це варіант злиття знизу вгору, який працює, трактуючи вхід як об'єднання декількох різних відсортованих діапазонів, а потім використовуючи алгоритм злиття, щоб об'єднати їх разом. Ви повторюєте цей процес, поки не буде відсортовано весь діапазон введення. Це запускається в O (n) час, якщо дані вже відсортовані, а O (n lg n) в гіршому випадку. Це дуже елегантно, хоча на практиці це не так добре, як деякі інші адаптивні сорти, такі як Timsort або smoothsort.
Сортування вставки потребує часу O (n + кількість інверсій).
Інверсія - пара (i, j)такаi < j && a[i] > a[j] . Тобто, пара поза замовленням.
Одним із показників "майже відсортованого" є кількість інверсій --- можна вважати "майже відсортованими даними", щоб означати дані з малою кількістю інверсій. Якщо вам відомо, що кількість перетворень буде лінійною (наприклад, ви щойно додали елементи O (1) до відсортованого списку), сортування вставки потребує часу O (n).
Як і всі інші сказали, будьте обережні наївні Quicksort - це може мати продуктивність O (N ^ 2) на відсортованих або майже відсортованих даних. Тим не менш, з відповідним алгоритмом для вибору стрижня (випадкового або середнього з трьох - див. Вибір стрижня для Quicksort опорного пункту для Quicksort) Quicksort все одно працюватиме нормально.
Взагалі, складність у виборі таких алгоритмів, як сортування вставок, полягає у визначенні того, коли дані достатньо вийшли з ладу, що Quicksort справді був би швидшим.
Я не збираюся робити вигляд на всі відповіді тут, тому що я думаю, що для отримання фактичних відповідей може знадобитися кодування алгоритмів та їх профілювання щодо репрезентативних зразків даних. Але я думав над цим питанням увесь вечір, і ось, що мені траплялося дотепер, і деякі здогадки про те, що найкраще працює де.
Нехай N - кількість елементів, загальна, M - кількість поза замовленням.
Сорт бульбашки повинен буде зробити щось на зразок 2 * M + 1, що проходить через усі N елементів. Якщо M дуже маленький (0, 1, 2?), Я думаю, що це буде дуже важко перемогти.
Якщо M невеликий (скажімо, менше, ніж log N), сортування вставки матиме великі середні показники. Однак, якщо є хитрість, яку я не бачу, вона матиме дуже погані показники. (Так? Якщо останній елемент у замовленні виходить першим, то вам доведеться вставляти кожен окремий елемент, наскільки я бачу, що вбиває продуктивність.) Я здогадуюсь, що для цього є більш надійний алгоритм сортування. випадку, але я не знаю, що це.
Якщо M більший (скажімо, рівний або великий, ніж log N), інтроспективний сортування майже напевно найкращий.
Виняток із всього цього: Якщо ви фактично знаєте заздалегідь, які елементи несортовані, то найкращою вашою ставкою буде витягнути ці елементи, сортувати їх за допомогою інтроспективного сортування та об’єднати два відсортовані списки разом у один відсортований список. Якщо ви зможете швидко розібратися, які предмети вийшли з ладу, це також було б хорошим загальним рішенням, - але я не зміг зрозуміти простий спосіб зробити це.
Подальші думки (протягом ночі): Якщо M + 1 <N / M, ви можете сканувати список, шукаючи пробіг N / M у рядку, відсортованому, а потім розгорнути його в будь-якому напрямку, щоб знайти вихід -порядкові предмети. Це займе щонайбільше 2N порівнянь. Потім ви можете сортувати несортовані елементи та робити відсортоване об’єднання за двома списками. Загальне порівняння повинно бути меншим, ніж щось на зразок 4N + M log2 (M), який, на мою думку, переможе будь-яку неспеціалізовану процедуру сортування. (Ще думка далі: це складніше, ніж я думав, але я все ще думаю, що це розумно можливо.)
Інша інтерпретація питання полягає в тому, що може бути багато предметів, що не вийшли з ладу, але вони дуже близькі до того, де вони повинні бути у списку. (Уявіть, що ви починаєте з відсортованого списку та заміняєте кожен інший предмет тим, що приходить після нього.) У такому випадку я думаю, що сортування міхура працює дуже добре - я думаю, що кількість пропусків буде пропорційним найбільш віддаленому від місця предмету є. Сортування вставки буде погано працювати, оскільки кожен елемент, який не входить у порядок, викликає вставку. Я підозрюю, що інтроспективний сорт чи щось подібне теж буде добре.
Якщо вам потрібна спеціальна реалізація для сортування алгоритмів, структур даних або будь-чого, що має посилання на вищезазначене, я можу порекомендувати вам чудові "Структури даних та алгоритми" на CodePlex?
У ньому буде все необхідне, не вигадуючи колесо.
Просто моє маленьке зерно солі.
Ця приємна колекція алгоритмів сортування для цієї мети у відповідях, здається, не має сортування Gnome Sort , що також було б придатним, і, ймовірно, вимагає найменших зусиль щодо впровадження.
розмірковуйте Спробуйте купи. Я вважаю, що це найбільш послідовний з видів O (n lg n).
Сортування бульбашок (або, ще безпечніше, двонаправлене сортування бульбашок), ймовірно, ідеально підходить для в основному відсортованих списків, хоча я ставлю на облік, що перероблений гребінець (із значно меншим початковим розміром проміжку) був би трохи швидшим, коли список не був ' t зовсім як ідеально відсортований. Сортування сортування деградує до сортування бульбашок.
ну це залежить від випадку використання. Якщо ви знаєте, які елементи змінені, видалення та вставлення буде найкращим випадком, що стосується мене.
Сорт бульбашки, безумовно, переможець Наступним на радарі буде сортування вставок.
Тримайтеся подалі від QuickSort - дуже неефективного для попередньо відсортованих даних. Встановлення сортування обробляє майже добре відсортовані дані, переміщуючи якомога менше значень.