Швидке сортування
Клас | Алгоритм сортування |
---|---|
Структура даних | Різні |
Найгірша швидкодія | |
Найкраща швидкодія | |
Середня швидкодія | |
Просторова складність у найгіршому випадку | Залежить від реалізації |
Оптимальний | Інколи |
Стабільний | Ні |
Швидке сортування (англ. Quick Sort) — алгоритм сортування, розроблений Тоні Гоаром, який не потребує додаткової пам'яті і виконує у середньому операцій. Однак, у найгіршому випадку робить порівнянь. Позаяк алгоритм використовує дуже прості цикли і операції, він працює швидше за інші алгоритми, що мають таку ж асимптотичну оцінку складності. Наприклад, зазвичай більш ніж удвічі швидший порівняно з сортуванням злиттям.
Ідея алгоритму полягає в переставлянні елементів масиву таким чином, щоб його можна було розділити на дві частини і кожний елемент з першої частини був не більший за будь-який елемент з другої. Впорядкування кожної з частин відбувається рекурсивно. Алгоритм швидкого сортування може бути реалізований як у масиві, так і в двозв'язному списку.
Швидке сортування є алгоритмом на основі порівнянь і не є стабільним.
Історія
Алгоритм швидкого сортування було розроблено Тоні Гоаром у 1962 під час роботи у маленькій британській компанії Elliott Brothers[en].[1]
Псевдокод алгоритму
Ця стаття потребує упорядкування для відповідності стандартам якості Вікіпедії. |
Класичний алгоритм
У класичному варіанті, запропонованому Гоаром,[2] з масиву обирали один елемент, а весь масив розбивали на дві частини за принципом: у першій частині — не більші за даний елемент, в другій — не менші за даний елемент. Процедура здійснює часткове впорядкування масиву з p-го по q-й індекс:
1 if return; 2 3 4 5 while do 6 repeat 7 8 until 9 repeat 10 11 until 12 if 13 then Swap 14 15
Сучасний алгоритм
Нині в стандартних бібліотеках використовують таку реалізацію алгоритму[3]:
1 2 3 for to 4 do if 5 then 6 7 Swap 8 Swap 8 return
Функція Partition повертає індекс з опорним елементом, що розділяє масив на дві частини; ліву — елементи якої менше опорного елементу, і праву — елементи якої більше опорного елементу. Всередині функції опорним елементом вибирається останній елемент масиву і обхід здійснюється починаючи з першого елементу, прирівнюючи його до опорного.
1 if return; 2 3 4
Аналіз
Час роботи алгоритму сортування залежить від збалансованості, що характеризує розбиття. Збалансованість у свою чергу залежить від того, який елемент обрано як опорний (відносно якого елемента виконується розбиття). Якщо розбиття збалансоване, то асимптотично алгоритм працює так само швидко як і алгоритм сортування злиттям. У найгіршому випадку асимптотична поведінка алгоритму настільки ж погана, як і в алгоритму сортування включенням.
Найгірше розбиття
Найгірша поведінка має місце у тому випадку, коли процедура, що виконує розбиття, породжує одну підзадачу з n-1 елементом, а другу — з 0 елементами. Нехай таке незбалансоване розбиття виникає при кожному рекурсивному виклику. Для самого розбиття потрібен час . Тоді рекурентне співвідношення для часу роботи можна записати так:
Розв'язком такого співвідношення є .
Найкраще розбиття
В найкращому випадку процедура Partition ділить задачу на дві підзадачі, розмір кожної не перевищує n/2. Час роботи описується нерівністю:
Тоді:
— асимптотично найкращий час.
Середній випадок
Математичне очікування часу роботи алгоритму на всіх можливих вхідних масивах є , тобто середній випадок ближчий до найкращого.
Модифікації
В середньому алгоритм працює дуже швидко, але на практиці не всі можливі вхідні масиви мають однакову імовірність. Тоді шляхом додання рандомізації вдається отримати середній час роботи в будь-якому випадку.
Рандомізованний алгоритм
В рандомізованному алгоритмі, при кожному розбитті випадковий елемент обирається як опорний:
1 2 Поміняти 9 return
1 if return; 2 3 4
Реалізація мовою Pascal
Цей розділ не містить посилань на джерела. (жовтень 2016) |
Ця процедура, після її оголошення, сортує масив mas, який складається з елементів типу integer.
Procedure QuickSort(first, last :integer);
Var v, x, left, right :integer;
begin
left := first;
right := last;
v := mas[(left + right) div 2];
while left <= right do
begin
while mas[left] < v do
left := left + 1;
while mas[right] > v do
right := right - 1;
if left <= right then
begin
x := mas[left];
mas[left] := mas[right];
mas[right] := x;
left := left + 1;
right := right - 1;
end;
end;
if first < right then
QuickSort(first, right);
if left < last then
QuickSort(left, last);
end;
Реалізація мовою C++
Цей розділ не містить посилань на джерела. (травень 2021) |
Ця функція сортує масив array, що містить n елементів, де right = n-1.
right-left+1: +1 для того, аби у виклику QuickSort (array, 0, 1) опорним елементом вибирався правий елемент, що не допустить спробу декрементувати j, коли ця змінна вже рівна 0.
template <typename T>
void QuickSort (T array[],
size_t const left,
size_t const right)
{
static T temp;
size_t i=left, j=right;
T pivot = array[left + ((right-left+1) >> 1)];
while (i <= j)
{
while (array[i] < pivot) ++i;
while (array[j] > pivot) --j;
if (i <= j)
{
temp = array[i];
array[i] = array[j];
array[j] = temp;
++i;
--j;
}
}
if (j > left)
QuickSort (array, left, j);
if (i < right)
QuickSort (array, i, right);
}
Реалізація мовою JavaScript[4]
Функція quickSort приймає масив arr як вхідний параметр і повертає відсортований масив.
function quickSort(arr) {
if (arr.length <= 1) {
return arr;
}
const pivot = arr[Math.floor(arr.length / 2)];
const less = [];
const greater = [];
for (let i = 0; i < arr.length; i++) {
if (arr[i] < pivot) {
less.push(arr[i]);
} else if (arr[i] > pivot) {
greater.push(arr[i]);
}
}
return [...quickSort(less), pivot, ...quickSort(greater)];
}
// Приклад використання:
const array = [5, 3, 1, 6, 2, 4];
const sortedArray = quickSort(array);
console.log(sortedArray);
// Результат
// [1, 2, 3, 4, 5, 6]
Реалізація мовою Ruby[5]
Метод quick_sort приймає масив arr як вхідний параметр і повертає відсортований масив.
def quick_sort(arr)
return arr if arr.length <= 1
pivot = arr[arr.length / 2]
less = []
greater = []
arr.each do |element|
if element < pivot
less << element
elsif element > pivot
greater << element
end
end
return [*quick_sort(less), pivot, *quick_sort(greater)]
end
# Приклад використання:
array = [5, 3, 1, 6, 2, 4]
sorted_array = quick_sort(array)
puts sorted_array
# Результат
# [1, 2, 3, 4, 5, 6]
Примітки
- ↑ Timeline of Computer History: 1960. Computer History Museum. Архів оригіналу за 25 червня 2013. Процитовано 5 січня 2009.
- ↑ Т. Кормен; Ч. Лейзерсон; Р. Рівест; К. Стайн (2009) [1990]. Розділ 7. Швидке сортування. Вступ до алгоритмів (вид. 3rd). MIT Press і McGraw-Hill. ISBN 0-262-03384-4.
- ↑ Т. Кормен; Ч. Лейзерсон; Р. Рівест; К. Стайн (2009) [1990]. Розділ 7: Швидке сортування. Вступ до алгоритмів (вид. 3rd). MIT Press і McGraw-Hill. ISBN 0-262-03384-4.
- ↑ Приклад QuickSort алгоритму (JavaScript). tseivo.com. Процитовано 5 липня 2023.
- ↑ Приклад QuickSort алгоритму (Ruby). tseivo.com. Процитовано 5 липня 2023.
Література
- Т. Кормен; Ч. Лейзерсон; Р. Рівест; К. Стайн (2009) [1990]. 7 Швидке сортування. Вступ до алгоритмів (вид. 3rd). MIT Press і McGraw-Hill. ISBN 0-262-03384-4.
Посилання
- Реалізація алгоритму швидкого сортування різними мовами програмування [Архівовано 7 лютого 2015 у Wayback Machine.]
- Реалізації алгоритму швидкого сортування різними мовами програмування в стилі грамотного програмування [Архівовано 9 травня 2008 у Wayback Machine.]
- Animated Sorting Algorithms: Quick Sort — графічна демонстрація роботи алгоритму
- Animated Sorting Algorithms: 3-Way Partition Quick Sort — графічна демонстрація алгоритму швидкого сортування з розбиттям масиву на три частини.
- Наочна демонстрація швидкого сортування угорськими танцюристами. [Архівовано 7 червня 2014 у Wayback Machine.]
- Interactive Tutorial for Quicksort [Архівовано 3 лютого 2009 у Wayback Machine.]
- Analyze Quicksort in an online Javascript IDE
- Javascript Quicksort and Bubblesort
- Quicksort applet
- Multidimensional quicksort in Java
- Quicksort tutorial with illustrated examples