Radix sort (sortowanie pozycyjne)
Ostatnia aktualizacja
Radix sort to sortowanie bez porównań dla liczb całkowitych. Zamiast porównywać wartości, sortuje liczby cyfra po cyfrze. Wersja od najmniej znaczącej cyfry (LSD) przetwarza najpierw cyfrę jedności, potem dziesiątek, potem setek, używając w każdej pozycji stabilnego sortowania przez zliczanie. Ponieważ każdy przebieg jest stabilny, po przetworzeniu najbardziej znaczącej cyfry cała tablica jest posortowana. Kliknij odtwarzanie powyżej i zobacz, jak każdy przebieg po cyfrze zmienia kolejność słupków.
Radix sort działa w czasie O(d·(n + k)), gdzie d to liczba cyfr, a k to podstawa systemu (tutaj 10). Dla liczb całkowitych o stałej szerokości jest to w praktyce czas liniowy, który może pokonać sortowania przez porównania O(n log n), ale algorytm działa tylko na danych, które da się rozłożyć na cyfry lub klucze.
Złożoność czasowa i pamięciowa
| Przypadek | Złożoność | Uwagi |
|---|---|---|
| Czas | O(d·(n + k)) | d cyfr, podstawa k (liniowy dla stałego d) |
| Pamięć | O(n + k) | Tablica wynikowa + liczniki cyfr |
| Stabilne | Tak | Każdy przebieg po cyfrze to stabilne sortowanie przez zliczanie |
| Porównania? | Nie | Sortuje po cyfrach, a nie przez porównywanie wartości |
| Działa na | Liczbach całkowitych/kluczach | Nie na dowolnych porównywalnych obiektach |
Krok po kroku
| Krok | Co się dzieje |
|---|---|
| 1 | Znajdź wartość maksymalną, aby wiedzieć, ile cyfr przetworzyć. |
| 2 | Zacznij od najmniej znaczącej cyfry (pozycji jedności). |
| 3 | Posortuj tablicę stabilnie według tej cyfry za pomocą sortowania przez zliczanie. |
| 4 | Przejdź do następnej, bardziej znaczącej cyfry. |
| 5 | Powtarzaj, aż wszystkie pozycje cyfr zostaną przetworzone. |
Przykład krok po kroku
Sortowanie [170, 45, 75, 90, 2, 24, 66]:
| Przebieg | Tablica | Działanie |
|---|---|---|
| Start | [170, 45, 75, 90, 2, 24, 66] | Maksimum to 170, więc potrzebne są trzy przebiegi po cyfrach. |
| Jedności | [170, 90, 2, 24, 45, 75, 66] | Stabilne sortowanie według cyfry jedności: 0, 0, 2, 4, 5, 5, 6. |
| Dziesiątki | [2, 24, 45, 66, 170, 75, 90] | Stabilne sortowanie według cyfry dziesiątek: 0, 2, 4, 6, 7, 7, 9 (170 pozostaje przed 75). |
| Setki | [2, 24, 45, 66, 75, 90, 170] | Stabilne sortowanie według cyfry setek; tylko 170 ma 1, więc trafia na koniec. Posortowane. |
Kiedy używać sortowania pozycyjnego
| Używaj, gdy | Unikaj, gdy |
|---|---|
| Klucze to liczby całkowite lub napisy o stałej długości, które da się podzielić na cyfry. | Musisz sortować dowolne obiekty własnym komparatorem. |
Klucze mają małą, ograniczoną liczbę cyfr d, więc O(d·(n + k)) pokonuje O(n log n). | Klucze są bardzo długie lub nieograniczone, przez co d jest duże, a przebiegi kosztowne. |
Potrzebujesz stabilnego sortowania i stać cię na O(n + k) dodatkowej pamięci. | Pamięci jest mało, a bufory O(n + k) są nie do przyjęcia. |
Zakres wartości lub podstawa k są umiarkowane w stosunku do n. | k jest ogromne, więc każdy przebieg sortowania przez zliczanie dominuje czas działania. |
Radix Sort: kod
Przejrzysta, gotowa do uruchomienia implementacja algorytmu Radix Sort w językach: Python, JavaScript, Java, C++, C. Wybierz język, skopiuj kod albo otwórz go od razu w edytorze online Coddy.
Radix Sort: kod (Python)
1def radix_sort(a):2 # Sort by each decimal digit, least significant first3 max_value = max(a)4 exp = 15 while max_value // exp > 0:6 a = sort_by_digit(a, exp)7 exp *= 108 return a9
10
11def sort_by_digit(a, exp):12 buckets = [[] for _ in range(10)]13 for value in a:14 digit = (value // exp) % 1015 buckets[digit].append(value)16 # Concatenating buckets 0..9 keeps the sort stable17 return [value for bucket in buckets for value in bucket]18
19
20nums = [170, 45, 75, 90, 802, 24, 2, 66]21print("Before:", nums)22print("After: ", radix_sort(nums))Radix Sort: kod (JavaScript)
1function radixSort(arr) {2 let a = [...arr];3 const max = Math.max(...a);4 // One counting pass per digit, least significant first5 for (let exp = 1; Math.floor(max / exp) > 0; exp *= 10) {6 const buckets = Array.from({ length: 10 }, () => []);7 for (const x of a) {8 buckets[Math.floor(x / exp) % 10].push(x);9 }10 a = buckets.flat();11 }12 return a;13}14
15const data = [170, 45, 75, 90, 802, 24, 2, 66];16console.log("Before:", data);17console.log("Sorted:", radixSort(data));Radix Sort: kod (Java)
1import java.util.Arrays;2
3public class Main {4 static void radixSort(int[] arr) {5 int max = 0;6 for (int v : arr) max = Math.max(max, v);7 // One stable counting pass per decimal digit8 for (int exp = 1; max / exp > 0; exp *= 10) countingPass(arr, exp);9 }10
11 static void countingPass(int[] arr, int exp) {12 int n = arr.length;13 int[] out = new int[n];14 int[] count = new int[10];15 for (int v : arr) count[(v / exp) % 10]++;16 for (int i = 1; i < 10; i++) count[i] += count[i - 1];17 // Walk backwards to keep the pass stable18 for (int i = n - 1; i >= 0; i--) {19 int digit = (arr[i] / exp) % 10;20 out[--count[digit]] = arr[i];21 }22 System.arraycopy(out, 0, arr, 0, n);23 }24
25 public static void main(String[] args) {26 int[] arr = {170, 45, 75, 90, 802, 24, 2, 66};27 System.out.println("Before: " + Arrays.toString(arr));28 radixSort(arr);29 System.out.println("After: " + Arrays.toString(arr));30 }31}Radix Sort: kod (C++)
1#include <algorithm>2#include <iostream>3#include <vector>4
5void printVec(const std::vector<int>& a) {6 for (int x : a) std::cout << x << " ";7 std::cout << "\n";8}9
10// Stable counting sort on one decimal digit (exp = 1, 10, 100, ...)11void countingPass(std::vector<int>& a, int exp) {12 std::vector<int> output(a.size());13 std::vector<int> count(10, 0);14 for (int x : a) ++count[(x / exp) % 10];15 for (int d = 1; d < 10; ++d) count[d] += count[d - 1];16 for (int i = static_cast<int>(a.size()) - 1; i >= 0; --i) {17 int digit = (a[i] / exp) % 10;18 output[--count[digit]] = a[i];19 }20 a = output;21}22
23void radixSort(std::vector<int>& a) {24 int maxVal = *std::max_element(a.begin(), a.end());25 for (int exp = 1; maxVal / exp > 0; exp *= 10) {26 countingPass(a, exp);27 }28}29
30int main() {31 std::vector<int> data = {170, 45, 75, 90, 802, 24, 2, 66};32 std::cout << "Before: ";33 printVec(data);34 radixSort(data);35 std::cout << "After: ";36 printVec(data);37 return 0;38}Radix Sort: kod (C)
1#include <stdio.h>2#include <stdlib.h>3
4void printArr(const int a[], int n) {5 for (int i = 0; i < n; i++) printf("%d ", a[i]);6 printf("\n");7}8
9// Stable counting sort on one decimal digit (exp = 1, 10, 100, ...)10void countingPass(int a[], int n, int exp) {11 int* output = malloc(n * sizeof(int));12 int count[10] = {0};13 for (int i = 0; i < n; i++) count[(a[i] / exp) % 10]++;14 for (int d = 1; d < 10; d++) count[d] += count[d - 1];15 for (int i = n - 1; i >= 0; i--) {16 int digit = (a[i] / exp) % 10;17 output[--count[digit]] = a[i];18 }19 for (int i = 0; i < n; i++) a[i] = output[i];20 free(output);21}22
23void radixSort(int a[], int n) {24 int maxVal = a[0];25 for (int i = 1; i < n; i++) {26 if (a[i] > maxVal) maxVal = a[i];27 }28 for (int exp = 1; maxVal / exp > 0; exp *= 10) {29 countingPass(a, n, exp);30 }31}32
33int main(void) {34 int data[] = {170, 45, 75, 90, 802, 24, 2, 66};35 int n = sizeof(data) / sizeof(data[0]);36 printf("Before: ");37 printArr(data, n);38 radixSort(data, n);39 printf("After: ");40 printArr(data, n);41 return 0;42}Radix sort: najczęstsze pytania
Jaka jest złożoność czasowa sortowania pozycyjnego?
O(d·(n + k)), gdzie d to liczba cyfr, a k to podstawa. Dla liczb całkowitych o stałej szerokości jest to w praktyce O(n), co może być szybsze od sortowań przez porównania. Zużywa O(n + k) dodatkowej pamięci.Czy sortowanie pozycyjne jest stabilne?
Kiedy mogę użyć sortowania pozycyjnego?
Czym różni się radix sort od sortowania przez zliczanie?
k), co pozwala obsłużyć duże zakresy wartości, z którymi zwykłe sortowanie przez zliczanie by sobie nie poradziło.