Педагогічний вимір
Через свою простоту метод розподілу Ломуто може бути простішим у застосуванні. У « Перлині програмування Джона Бентлі про сортування» є приємний анекдот :
"Більшість дискусій про Quicksort використовують схему розподілу, засновану на двох наближаються індексах [...] [тобто Хоара]. Хоча основна ідея цієї схеми відверта, я завжди вважав деталі складними - одного разу я провів більшу частину двох днів, переслідуючи помилку, ховаючись у короткому циклі перегородки. Читач попереднього проекту скаржився, що стандартний двоіндексний метод насправді простіший, ніж Ломуто, і накреслив якийсь код, щоб зробити свою думку; Я перестав доглядати, коли знайшов двох помилок ».
Вимір продуктивності
Для практичного використання простота реалізації може бути принесена в жертву заради ефективності. На теоретичній основі ми можемо визначити кількість порівнянь елементів та свопів для порівняння продуктивності. Крім того, на фактичний час роботи впливатимуть інші фактори, такі як ефективність кешування та непередбачувані гілки.
Як показано нижче, алгоритми поводяться дуже схоже на випадкові перестановки, за винятком кількості свопів . Там Ломуто потрібно втричі більше, ніж Хоаре!
Кількість порівнянь
Обидва способи можуть бути реалізовані за допомогою порівнянь для розподілу масиву довжиною . Це по суті оптимально, оскільки нам потрібно порівняти кожен елемент зі стрижнем, щоб визначити, куди його розмістити.nn−1n
Кількість свопів
Кількість свопів є випадковим для обох алгоритмів, залежно від елементів масиву. Якщо припустити випадкові перестановки , тобто всі елементи виразні і кожна перестановка елементів однаково вірогідна, ми можемо проаналізувати очікувану кількість свопів.
Як лише відносний підрахунок порядку, ми вважаємо, що елементами є числа . Це полегшує обговорення нижче, оскільки ранг елемента та його значення збігаються.1,…,n
Метод Ломуто
Змінна індексу сканує весь масив і кожного разу, коли ми знайдемо елемент менший за pivot , робимо своп. Серед елементів , рівно менше, ніж , тому ми отримуємо підкачки, якщо шарнір .A [ j ] x 1 , … , njA[j]x1,…,nx−1xx−1x
Тоді загальне очікування призводить до усереднення за всіма стрибками. Кожне значення в однаковою ймовірністю стане опорним (а саме з . ), тому у нас є{1,…,n}1n
1n∑x=1n(x−1)=n2−12.
поміняє в середньому для розподілу масиву довжиною методом Ломуто.n
Метод Хоара
Тут аналіз трохи складніше: Навіть фіксуючи pivot , кількість свопів залишається випадковою.x
Точніше: індекси та біжать назустріч один одному до тих пір, поки вони не перетинаються, що завжди відбувається при (правильність алгоритму розподілу Хоара!). Це ефективно ділить масив на дві частини: ліву частину, яку сканує і праву частину, відскановану .ijxij
Тепер робиться заміна точно для кожної пари "неправильно розміщених" елементів, тобто великого елемента (більший за , таким чином належить до правої секції), який зараз знаходиться в лівій частині, і невеликий елемент, розташований у правій частині. Зауважте, що ця форма формування пари завжди працює, тобто кількість малих елементів, спочатку в правій частині, дорівнює кількості великих елементів у лівій частині.x
Можна показати, що число цих пар розподілено гіпергеометрично : Для великих елементів ми випадково малюємо їхні позиції у масиві та маємо позиції у ліва частина. Відповідно, очікувана кількість пар дорівнює враховуючи, що шарнір дорівнює .Hyp(n−1,n−x,x−1)n−xx−1(n−x)(x−1)/(n−1)x
Нарешті, ми повторюємо середнє значення за всіма зведеними значеннями, щоб отримати загальну очікувану кількість свопів для розділення Хоара:
1n∑x=1n(n−x)(x−1)n−1=n6−13.
(Більш детальний опис можна знайти в магістерській роботі , сторінка 29.)
Шаблон доступу до пам'яті
Обидва алгоритми використовують два вказівники в масив, які послідовно сканують його . Тому обидва ведуть майже оптимальне кешування Wrt.
Рівні елементи та вже відсортовані списки
Як уже згадувала Wandering Logic, продуктивність алгоритмів відрізняється більш різко для списків, які не є випадковими перестановками.
У масиві, який вже відсортований, метод Хоара ніколи не змінюється, оскільки немає неправильно встановлених пар (див. Вище), тоді як метод Ломуто все ще робить приблизно підміни!n/2
Наявність рівних елементів вимагає особливої обережності у Quicksort. (Я вступив у цю пастку сам; дивіться магістерську дисертацію , стор. 36, для «Казки про передчасну оптимізацію») Розгляньте як крайній приклад масив, заповнений с. У такому масиві метод Хоара здійснює своп для кожної пари елементів - що є найгіршим випадком для розділення Хоара - але і завжди зустрічаються в середині масиву. Таким чином, ми маємо оптимальний розподіл і загальний час роботи залишається в .i j O ( n журналу n )0ijO(nlogn)
Метод Ломуто поводиться набагато тупіше на всіх масивах : Порівняння завжди буде правдивим, тому ми робимо своп для кожного окремого елемента ! Але ще гірше: після циклу ми завжди маємо , тому спостерігаємо найгірший випадок поділу, зробивши загальну продуктивність погіршенням до !i = n Θ ( n 2 )0A[j] <= x
i=nΘ(n2)
Висновок
Метод Ломуто простий і простий у здійсненні, але його не слід використовувати для впровадження методу сортування бібліотеки.
A[i+1] <= x
. У відсортованому масиві (з урахуванням обґрунтованих обертів) Хоар майже не проводить свопів, і Ломуто робить тонну (раз j стає достатньо маленькою, то всіA[j] <= x
.) Що мені не вистачає?