Цивільно-імперські послуги; структурне будівництво
Реалізація пряжки Сортування для Floating Point Numbers на Python
Table of Contents
Вступ до сорту пряжки для Floating-Point
Сорт ковша - алгоритм сортування розподільних частин, які перегородки вхідні дані в кінцеву кількість «греків», а потім сортують вміст кожного відро індивідуально. При нанесенні на плаваючі числа, які рівномірно розподілені над відомим інтервалом, зазвичай — сорт відра може досягати лінійної середньої складності в середньому місці, що робить його сильним кандидатом для високопродуктивних задач сортування.
Основна ідея проста: замість порівняння кожної пари елементів (як у порівнянні сорту, так і швидко розсмоктування), відро сорту спочатку розподіляє елементи по відрох на основі їх значень. Кожен відро природним чином груп разом з вузьким діапазоном значень. Після цього простий алгоритм сортування — часто вставки або навіть рекурсивний дзвінок до відро сорту — закінчує роботу. Нарешті, відро розкопані для того, щоб виготовити сортований масив.
У статті представлено поглиблений вигляд для реалізації сорту ковро для плаваючих чисел на Python, що охоплює механіки, складність, міцність, підводні камені та реальні програми світу.
Як сортувати ковша
Сорт ковша передбачає, що вхід рівномірно розподілений в межах відомого діапазону, як правило . Алгоритм протікає в трьох фазах:
- // Вісник: : Створюємо масив n] порожні відро, де n] ] — кількість елементів.
- Distribution]: Для кожного елемента , складіть його індекс відро (збільшувальні значення знаходяться в ) і розміщуйте елемент в цей відро.
- Корпорація та конкатенація: Сортувати кожен відро індивідуально (з будь-яким стійким або ефективним внутрішнім типом), потім захопити відро для отримання остаточного сортованого масиву.
Ключовий інсайт полягає в тому, що дані рівномірно розподілені, кожен відро отримує грубо n / n = 1] елемент в середньому. Це зберігає вартість сортування окремих відро вкрай низький — часто постійний час на відро.
Рукаючий край Кейси
Коли плаваючий номер точно дорівнює 1,0, то обчислений індекс буде , який з меж. Поширенийфікс полягає в тому, щоб зафіксувати індекс для таких значень. На практиці, якщо ваші дані суворі , цей крайовий випадок не відбувається, але це мудро, щоб захистити його від нього.
Реалізація пряжки Сортування на Python
Нижче наведено чистий, виробничо-прочитаний формат відра для плаваючих-точкових чисел в діапазоні .
def bucket_sort(arr):
"""Sort an array of floats uniformly distributed in [0, 1)."""
n = len(arr)
if n <= 1:
return arr
# Create empty buckets
buckets = [[] for _ in range(n)]
# Distribute elements into buckets
for num in arr:
index = int(num * n)
# Guard against floating-point index = n (e.g., when num == 1.0)
if index == n:
index = n - 1
buckets[index].append(num)
# Sort each bucket and concatenate
sorted_arr = []
for bucket in buckets:
sorted_arr.extend(sorted(bucket)) # Python's Timsort is efficient
return sorted_arr
Функція використовує вбудовані панелі Python для сортування кожного відро. Для відро, які є маленькими (типово 0–2 елементи), це дуже швидко. Для використання виробництва, ви можете замінити з вставкою сорту для навіть нижньої накладки на крихітних відро.
Сорт пряжки для Арбітричних діапазонів
Якщо ваші плаваючі дані протяжують діапазон, крім , ви можете нормалізувати значення до розподілу. Наступні варіації карти будь-якого діапазону :
def bucket_sort_scaled(arr, min_val=None, max_val=None):
if not arr:
return arr
if min_val is None:
min_val = min(arr)
if max_val is None:
max_val = max(arr)
# Guard against identical values
if max_val == min_val:
return arr
n = len(arr)
buckets = [[] for _ in range(n)]
for num in arr:
# Normalize to [0, 1)
normalized = (num - min_val) / (max_val - min_val)
index = int(normalized * n)
if index == n:
index = n - 1
buckets[index].append(num)
sorted_arr = []
for bucket in buckets:
sorted_arr.extend(sorted(bucket))
return sorted_arr
Ця версія є більш загальним, але вимагає ознайомлення або обчислення діапазону. Вона добре працює, коли розподіл даних є приблизно однорідною в межах цього діапазону.
Аналіз комплексності
Розуміння обчислювальної вартості сорту відра є важливим для його видалення.
Комплексність
- Кращий випадок O(n + k)], де k] є число відро (звичай n]]]]. Розподіл O(n)]]], і сортування кожного відро займає постійний час на середній, так загальний On]]O(n)]].
- : O(n + n2/k)], якщо використовувати вставку сорту для відро. k = n], це стає O(n)].
- Попередня справа]: O(n2)], коли всі елементи потрапляють в той самий відро. Це відбувається, коли дані не рівномірно розподілені, або коли діапазон дуже мало відносно кількості елементів.
Космічна комплексність
Сорт ковша вимагає O(n + k)] додаткового простору для відро і їх вмісту. З k = n], це O(n)]. Місце, що використовується, є порівняти з цим з концентрацією і вище, ніж у місці, такі як швидке сусла.
Переваги та використання випадків
Сорт ковша захоплюється в конкретних сценаріях, де його припущення проводяться:
- Неформно розподілені плаваючі дані — наприклад, сенсорні читання, Монте-Карло імітаційні виходи, або нормалізовані ймовірності.
- Large datasets — O(n)] середньо-червоний результат робить його привабливим для сортування мільйонів плавань, де порівняння сортів буде менш ефективним.
- Попередня сортування] — коли дані залишають на диску, відро можна обробити самостійно і письмово на окремі файли, потім приховати.
- Parallel і GPU обчислення — кожен відро можна сортувати самостійно, що дозволяє масивний паралельний алгоритм.
Одна нездатна міцність полягає в тому, що сорт відра розклад] (якщо стійкий сорт пер-грека), що означає відносне замовлення рівних елементів.
Обмеження та роздуми
Незважаючи на свою елегантність, сорт відра має кілька обмежень, які можуть надати йому невідповідність для загального сортування:
- ]Сенситивність вводу розподілу: Якщо дані скошовані (наприклад, багато значень кластеровані разом), більшість елементів потрапляють в кілька відро, збільшення вартості сортування до O(n2).
- Вимагає до знань діапазону: Без знання мінімальних і максимальних значень, ви не можете ефективно створювати відро. Визначена версія вище пом'якшує цей, але обчислює діапазон додає додатковий прохід.
- : Створення n] // Список Python може споживати значну пам'ять, особливо для дуже великих масивів. Списки посилань або масиви масивів можуть зменшити наклад, але список списків Python є прямим.
- Overhead of per-bucket sorting: Сортування багато крихітних відро з Python виробляє функціональні дзвінки, які можуть додавати. Для надзвичайно малих відро, чіткий сорт вставки може бути швидше.
Коли не використовувати пряжку Сортувати
Уникайте відро сорту, коли дані не рівномірно розподілені, коли діапазон дуже великий відносно кількості елементів, або коли пам'ять надзвичайно обмежена. У тих випадках, як порівняння , кальмар або ] / heapsort - це найбезпечніший вибір.
Порівняння з іншими алгоритмами сортування
Сорт пряжки займає унікальну нішу серед алгоритмів сортування. Ось як вона порівнює загальні альтернативи:
| Algorithm | Average Time | Space | Stable | Best For |
|---|---|---|---|---|
| Bucket Sort (with k = n) | O(n) | O(n) | Yes (if per-bucket sort is stable) | Uniform floats in known range |
| Quicksort | O(n log n) | O(log n) | No (typical) | General-purpose, in-place |
| Mergesort | O(n log n) | O(n) | Yes | Stable sorting, linked lists |
| Counting Sort | O(n + k) | O(k) | Yes | Integer data with limited range |
| Radix Sort | O(n × w) | O(n + 2^w) | Yes (LSD) | Integers or strings of fixed length |
Для плаваючих чисел, відро сорт часто неперетворює сорт редикс (який вимагає біт-маніпуляції плавок) і може бути швидше, ніж O(n log n) порівняння сортує при однорідності даних.
Практичні поради та оптимізація Python
Вибір кількості греків
Встановлення кількості відро, що дорівнює кількості елементів (k = n]) є стандартним правилом великого пальця. Відро відра приростає середній розмір відра і деградує продуктивність; більше відро відходи пам'яті без підвищення швидкості.
Використання Сортування заборів для малих пряжок
Якщо ви хочете тонкозернувати контроль, замініть з користувальницький вставляння сорту для відро менша, ніж, скажте, 20 елементів:
def insertion_sort(arr):
for i in range(1, len(arr)):
key = arr[i]
j = i - 1
while j >= 0 and arr[j] > key:
arr[j + 1] = arr[j]
j -= 1
arr[j + 1] = key
def bucket_sort_insertion(arr):
n = len(arr)
if n <= 1:
return arr
buckets = [[] for _ in range(n)]
for num in arr:
index = int(num * n)
if index == n:
index = n - 1
buckets[index].append(num)
sorted_arr = []
for bucket in buckets:
insertion_sort(bucket)
sorted_arr.extend(bucket)
return sorted_arr
Це може зменшити надголову, оскільки Python має функцію-загальнюючу покладну та універсальну поведінку, яка є надвигаючим для 0- або 1-вирівнюючих списків.
Обробка неоднорідних розподілів
Якщо ви знаєте розподіл даних неоднорідний, але все ще хочете використовувати відро сорту, можна адаптувати межі відро. Наприклад, якщо дані слідують нормальному розподілу, можна створити відро від нерівної ширини для балансування навантаження. Однак це вимагає попереднього аналізу даних і рідко проводиться на практиці.
Зовнішні ресурси
Для подальшого читання вкажіть наступні авторизовані посилання:
- Вікіпедія: Сорт пряжки — детальний опис і складність доказів.
- GeeksforGeeks: Сорт пряжки — з прикладами коду на декількох мовах.
- документація] — розуміння основного Тимсорту.
- Real Python: Сортування алгоритмів на Python — практичний посібник, що порівняти відро відсорт до інших алгоритмів.
Висновок
Сорт ковша - це елегантний, ефективний алгоритм сортування плаваючих чисел - особливо коли дані рівномірно розподілені і діапазон відомий. Його лінійна середня тривалість вери робить його цінним інструментом в інструментальному положенні або інженера даних. Однак, його чутливість до розподілу вхідних даних і додаткові вимоги до пам'яті, що не повинні бути використані сліпо. Розуміння, коли і як застосувати сорт відра, і шляхом реалізації його ретельно в Python з правильним керуванням з регістром, ви можете досягти значних результатів, надігаючи над загальними розмірами порівняння.
Якщо ви сортуєте мільйони вимірювань датчика або нормалізувати вихід з стохастичного моделювання, сорт відра пропонує швидкий, стабільний і паралельний розчин — до тих пір, поки ваші дані грає правила.