Radix Sort (מיון בסיס)
עודכן לאחרונה
Radix sort הוא מיון שאינו מבוסס השוואות, למספרים שלמים. במקום להשוות ערכים, הוא ממיין מספרים ספרה אחר ספרה. גרסת הספרה הפחות משמעותית (LSD) מטפלת קודם בספרת האחדות, אחר כך בעשרות, ואז במאות, בעזרת מיון מנייה יציב בכל ספרה. מכיוון שכל מעבר יציב, ברגע שמטפלים בספרה המשמעותית ביותר המערך כולו ממוין. לחצו על הפעלה למעלה כדי לראות כל מעבר ספרה מסדר מחדש את העמודות.
Radix sort רץ בזמן O(d·(n + k)), כאשר d הוא מספר הספרות ו-k הוא הבסיס (כאן 10). עבור מספרים שלמים ברוחב קבוע זה בפועל זמן ליניארי, והוא יכול לנצח מיונים מבוססי השוואה של O(n log n), אבל הוא עובד רק על נתונים שאפשר לפרק לספרות או למפתחות.
סיבוכיות זמן וזיכרון
| מקרה | סיבוכיות | הערות |
|---|---|---|
| זמן | O(d·(n + k)) | d ספרות, בסיס k (ליניארי עבור d קבוע) |
| זיכרון | O(n + k) | מערך פלט וספירות ספרות |
| יציב | כן | כל מעבר ספרה הוא מיון מנייה יציב |
| מבוסס השוואה? | לא | ממיין לפי ספרה, לא בהשוואת ערכים |
| עובד על | מספרים שלמים ומפתחות | לא על אובייקטים כלליים שניתנים להשוואה |
צעד אחר צעד
| צעד | מה קורה |
|---|---|
| 1 | מוצאים את הערך המקסימלי כדי לדעת בכמה ספרות לטפל. |
| 2 | מתחילים בספרה הפחות משמעותית (מקום האחדות). |
| 3 | ממיינים את המערך בצורה יציבה לפי הספרה הזו בעזרת מיון מנייה. |
| 4 | עוברים לספרה המשמעותית הבאה. |
| 5 | חוזרים על כך עד שמטפלים בכל מיקומי הספרות. |
דוגמה מפורטת
מיון של [170, 45, 75, 90, 2, 24, 66]:
| מעבר | מערך | פעולה |
|---|---|---|
| התחלה | [170, 45, 75, 90, 2, 24, 66] | המקסימום הוא 170, ולכן צריך שלושה מעברי ספרות. |
| אחדות | [170, 90, 2, 24, 45, 75, 66] | מיון יציב לפי ספרת האחדות: 0, 0, 2, 4, 5, 5, 6. |
| עשרות | [2, 24, 45, 66, 170, 75, 90] | מיון יציב לפי ספרת העשרות: 0, 2, 4, 6, 7, 7, 9 (170 שומר על מקומו לפני 75). |
| מאות | [2, 24, 45, 66, 75, 90, 170] | מיון יציב לפי ספרת המאות; רק ל-170 יש 1, ולכן הוא זז לסוף. ממוין. |
מתי להשתמש ב-radix sort
| השתמשו בו כאשר | הימנעו ממנו כאשר |
|---|---|
| המפתחות הם מספרים שלמים או מחרוזות באורך קבוע שאפשר לפרק לספרות. | אתם חייבים למיין אובייקטים כלשהם לפי פונקציית השוואה מותאמת. |
למפתחות יש מספר ספרות d קטן וחסום, כך ש-O(d·(n + k)) מנצח את O(n log n). | המפתחות ארוכים מאוד או לא חסומים, מה שהופך את d לגדול ואת המעברים ליקרים. |
אתם צריכים מיון יציב ויכולים להרשות לעצמכם O(n + k) זיכרון נוסף. | הזיכרון מוגבל והחוצצים של O(n + k) אינם מקובלים. |
טווח הערכים או הבסיס k צנוע ביחס ל-n. | k עצום, ולכן כל מעבר של מיון מנייה שולט בזמן הריצה. |
קוד Radix Sort
מימוש נקי של Radix Sort שאפשר להריץ, ב-Python, JavaScript, Java, C++, C. בחרו שפה, העתיקו את הקוד, או פתחו אותו טעון מראש בעורך האונליין של Coddy.
קוד Radix Sort ב-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 ב-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 ב-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 ב-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 ב-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
מהי סיבוכיות הזמן של radix sort?
O(d·(n + k)), כאשר d הוא מספר הספרות ו-k הוא הבסיס. עבור מספרים שלמים ברוחב קבוע זה בפועל O(n), וזה יכול להיות מהיר יותר ממיונים מבוססי השוואה. הוא משתמש ב-O(n + k) זיכרון נוסף.האם radix sort יציב?
מתי אפשר להשתמש ב-radix sort?
במה radix sort שונה ממיון מנייה?
k), וכך הוא מתמודד עם טווחי ערכים גדולים שמיון מנייה רגיל לא היה מסוגל להם.