Menu
Coddy logo textTech

Counting Sort (מיון מנייה)

עודכן לאחרונה

מיון מנייה הוא מיון שאינו מבוסס השוואות, למספרים שלמים בטווח ידוע ומוגבל. הוא סופר כמה פעמים מופיע כל ערך, ואז משתמש בספירות האלה כדי לכתוב כל ערך ישירות למקומו הממוין, בלי צורך בהשוואות. לחצו על הפעלה למעלה כדי לראות את הערכים נספרים ואז מוצבים בחזרה לפי הסדר.

מיון מנייה רץ בזמן O(n + k), כאשר k הוא טווח ערכי הקלט. כש-k לא גדול בהרבה מ-n הוא מהיר מאוד ויכול לנצח מיונים מבוססי השוואה של O(n log n), אבל אם טווח הערכים עצום, מערך הספירה של O(k) הופך אותו ללא מעשי.

סיבוכיות זמן וזיכרון

מקרהסיבוכיותהערות
זמןO(n + k)n איברים, k = טווח הערכים
זיכרוןO(n + k)מערך ספירה ומערך פלט
יציבכןכשמציבים מימין לשמאל בעזרת סכומים מצטברים
מבוסס השוואה?לאממיין בספירה, לא בהשוואה
הכי מתאים לטווח קטן של מספרים שלמיםk קרוב ל-n

צעד אחר צעד

צעדמה קורה
1מוצאים את הערך המקסימלי כדי לקבוע את גודל מערך הספירה.
2סופרים כמה פעמים מופיע כל ערך.
3(אופציונלי) הופכים את הספירות לסכומים מצטברים לשם יציבות.
4כותבים כל ערך לפלט מספר פעמים כמספר ההופעות שלו.
5מערך הפלט ממוין עכשיו לגמרי.

דוגמה מפורטת

מיון של [1, 4, 1, 2, 4] (הערכים נעים בין 0 ל-4, ולכן למערך הספירה יש 5 תאים):

שלבמצבפעולה
סריקת הקלטcount = [0, 2, 1, 0, 2]סופרים מופעים: 1 מופיע פעמיים, 2 פעם אחת, 4 פעמיים.
סכומים מצטבריםcount = [0, 2, 3, 3, 5]כל תא מחזיק עכשיו כמה ערכים הם <= לאינדקס שלו, וזה נותן את המיקומים הסופיים.
הצבת 4output = [_, _, _, _, 4]קוראים מימין לשמאל: count[4] = 5, ולכן 4 הולך לאינדקס 4; מקטינים ל-4.
הצבת 2output = [_, _, 2, _, 4]count[2] = 3, ולכן 2 הולך לאינדקס 2; מקטינים ל-2.
הצבת 1output = [_, 1, 2, _, 4]count[1] = 2, ולכן 1 הולך לאינדקס 1; מקטינים ל-1.
הצבת 4output = [_, 1, 2, 4, 4]count[4] = 4, ולכן ה-4 הזה הולך לאינדקס 3; מקטינים ל-3.
הצבת 1output = [1, 1, 2, 4, 4]count[1] = 1, ולכן ה-1 הזה הולך לאינדקס 0. המערך ממוין.

מתי להשתמש במיון מנייה

השתמשו בו כאשרהימנעו ממנו כאשר
ממיינים מספרים שלמים (או מפתחות שאפשר למפות למספרים שלמים) בטווח קטן וידוע.טווח הערכים k גדול בהרבה ממספר האיברים n.
אתם צריכים זמן ליניארי של O(n + k) ויכולים להרשות לעצמכם את המערכים הנוספים.הזיכרון מוגבל: מערך הספירה עולה O(k) בלי קשר ל-n.
אתם צריכים מיון יציב כשגרת עזר (למשל בתוך radix sort).המפתחות הם מספרים עשרוניים, מחרוזות או אובייקטים כלשהם בלי מיפוי למספרים שלמים.
הערך המקסימלי חסום וזול לחישוב מראש.הטווח לא ידוע או לא חסום, ולכן אי אפשר לקבוע את גודל מערך הספירה.

קוד Counting Sort

מימוש נקי של Counting Sort שאפשר להריץ, ב-Python, JavaScript, Java, C++, C. בחרו שפה, העתיקו את הקוד, או פתחו אותו טעון מראש בעורך האונליין של Coddy.

קוד Counting Sort ב-Python

Python
1def counting_sort(a):2    # Works for non-negative integers with a small max value3    counts = [0] * (max(a) + 1)4    for value in a:5        counts[value] += 16    # Prefix sums turn counts into final positions7    for i in range(1, len(counts)):8        counts[i] += counts[i - 1]9    out = [0] * len(a)10    for value in reversed(a):  # reversed keeps equal values stable11        counts[value] -= 112        out[counts[value]] = value13    return out14
15
16nums = [4, 2, 2, 8, 3, 3, 1]17print("Before:", nums)18print("After: ", counting_sort(nums))
להריץ את הקוד הזה בעורך ה-Python אונליין

שאלות נפוצות על מיון מנייה

מהי סיבוכיות הזמן של מיון מנייה?
מיון מנייה הוא O(n + k), כאשר n הוא מספר האיברים ו-k הוא טווח הערכים האפשריים. כש-k = O(n) זה זמן ליניארי. הוא משתמש ב-O(n + k) זיכרון נוסף.
האם מיון מנייה יציב?
הוא יכול להיות. הגרסה היציבה בונה סכומים מצטברים של הספירות ומציבה איברים מימין לשמאל, וכך נשמר הסדר היחסי של מפתחות שווים. הגרסה הפשוטה של "כתיבה מחדש לפי ערך" שמוצגת כאן מייצרת מיון נכון, אבל משמשת בעיקר למספרים שלמים פשוטים.
מתי כדאי להשתמש במיון מנייה?
השתמשו בו כשממיינים מספרים שלמים (או מפתחות שאפשר למפות למספרים שלמים) בטווח קטן וידוע. אם טווח הערכים k גדול בהרבה ממספר האיברים, מערך הספירה מבזבז זיכרון ומיון מבוסס השוואה עדיף.
מה ההבדל בין מיון מנייה ל-radix sort?
מיון מנייה ממיין לפי הערך השלם במעבר אחד וצריך מערך ספירה בגודל טווח הערכים. Radix sort ממיין ספרה אחר ספרה ובדרך כלל קורא למיון מנייה יציב על כל ספרה, וכך הטווח בכל מעבר נשאר קטן (למשל 10 לספרות עשרוניות). Radix sort מתמודד עם טווחי ערכים גדולים שהיו הופכים מיון מנייה יחיד ללא מעשי.
למה מיון מנייה לא תמיד מהיר יותר מ-quicksort?
מיון מנייה הוא O(n + k), ולכן הוא מנצח רק כשטווח הערכים k דומה בגודלו ל-n. אם k עצום, למשל מיון של 100 ערכים בטווח 0 עד 1,000,000,000, מערך הספירה של O(k) שולט ומבזבז זיכרון, ואילו מיון מבוסס השוואה של O(n log n) כמו quicksort נשאר מהיר וחסכוני בזיכרון.
האם מיון מנייה יכול להתמודד עם מספרים שליליים?
כן, עם היסט קטן. במקום לגשת למערך הספירה לפי הערך עצמו, ניגשים אליו לפי value - min, כך שהערך הקטן ביותר ממופה לאינדקס 0. גודל מערך הספירה הופך ל-max - min + 1. שכחה של ההיסט הזה היא באג נפוץ שקורס על קלטים שליליים.
איור של שפות התכנות ב-Coddy

לשלוט באלגוריתמים עם Coddy

להתחיל