מבני נתונים ואלגוריתמים - מחברת קורס/אלגוריתמים/החסם התחתון על מיון מבוסס-השוואות
מתוך ויקיספר, אוסף ספרי הלימוד והמדריכים החופשי.
כל שיטות המיון שראינו: מיון הכנסה, מיון מיזוג וQuicksort - כולן עבדו בסיבוכיות
במקרה הגרוע. האם אפשר לרדת נמוך מכך?
- באופן כללי, אי אפשר למיין בצורה יעילה יותר במקרה הגרוע. דף זה עוסק בזאת.
- בפרק הבא, אלגוריתמים למיון בזמן לינארי, נראה שאם הקלט מקיים הנחות נוקשות יחסית, אפשר למיין בצורה יעילה יותר גם במקרה הגרוע.
|
כדאי לדעת: בספר הקורס, הפרק "Sorting in Linear Time" עוסק בנושאים אלה. עם זאת, אנו נעסוק בנושא בגישה שונה מזו של הספר, גישה המבוססת על סיבוכיות קולמוגורוב. |
תוכן עניינים |
[עריכה] מיון מבוסס השוואות
|
הגדרה: מיון הוא מבוסס השוואות אם הוא מבסס את החלטותיו רק ע"י השוואת האיברים זה לזה, ולא על תכונות האיברים עצמם. |
|
דוגמה: להלן הפסוודו-קוד של מיון הכנסה. שים לב ל4, שם כתוב # Insertion sort. # Takes an array (Values). # Sorts the array in increasing order. Insertion-Sort(Values) 1 for i in [1, ..., Length(Values)] 2 v = Values[i] # Insert v into the correct position of Values[1, ..., i]. 3 j = i 4 while j > 1 and Values[j - 1] > v 5 Values[j] = Values[j - 1] 6 --j 7 Values[j] = v |
|
כדאי לדעת: כל אחד מהמיונים שראינו עד כה: מיון הכנסה, מיון מיזוג, וQuicksort - הנו מיון מבוסס-השוואות. באלגוריתמים למיון בזמן לינארי נראה מיונים שאינם מבוססי השוואות. |
מיון מבוסס-השוואות הוא במידה מסויימת המיון הכללי ביותר שיכול להיות, מפני שהוא מניח מעט מאוד לגבי מה שהוא ממיין: הוא יכול למיין מספרים שלמים, מספרי נקודה צפה, מחרוזות, ובעצם כל טיפוס שאפשר להשוות שני איברים מסוגו.
[עריכה] מגבלת מיון מבוסס-השוואות
בשאר הדף נוכיח את המשפט הבא.
|
משפט: כל מיון מבוסס-השוואות פועל במקרה הגרוע בזמן |
ההוכחה הנה קומבינטורית, ואינה קצרה במיוחד. שאר הדף עוסק בהוכחה.
[עריכה] בעיה קומבינטורית בקבצים
|
משפט: מספר הקבצים השונים, שאורך כל אחד מהם לכל היותר |
הוכחה: יש בדיוק קובץ אחד בעל 0 ביטים: הקובץ הריק. יש בדיוק 2 קבצים באורך 1 ביט: הקובץ המורכב מ"0", והקובץ המורכב מ"1". יש בדיוק 4 קבצים באורך 2 ביטים: אלה המורכבים מ"00", "01", "10", ו"11". באופן כללי, יש
קבצים באורך
ביטים. מספר הקבצים שאורך כל אחד מהם הוא לכל היותר
ביטים, הוא, לכן,
.
נוכל להשתמש בזאת כדי למצוא את מספר הביטים הנדרשים במקרה הגרוע לשמירת דברים שונים.
|
דוגמה: בתחנה מטאורולוגית מודדים מדי יום את הטמפרטורה, הנעה בין
כבר ראינו שיש |
|
דוגמה: מפעילים את תכנת הכיווץ bzip2 על כל הקבצים האפשריים באורך
|
[עריכה] בעיה קומבינטורית בפרמוטציות
|
הגדרה: נתונה קבוצה |
|
דוגמה: נניח שהקבוצה היא |
המשפט הבא טריביאלי.
|
דוגמה: אם |
אם נחבר את שתי הבעיות הקומבינטריות עליהן עברנו עד כה, נקבל את המשפט הבא.
|
משפט: נתונה קבוצה |
הוכחה: ראשית נשים לב שבדיוק כמו מקודם (כשדברנו על תכנית הכווץ), אין צורך שנחשוב איזה מידע בדיוק נרשום כדי שנוכל לשחזר את הפרמוטציה. הטענה שוב קומבינטורית. נשים לב שיש בדיוק
פרמוטציות, ויש
קבצי פלט שונים. נפתור
, ונקבל







(את המעבר האחרון ראינו כבר בטורים שימושיים בסדרי גדילה.)
[עריכה] מיון מבוסס-השוואות ופרמוטציות
כעת נראה שכל אלגוריתם מיון מבוסס-השוואות יכול לשמש לכתיבת קובץ המתאר פרמוטציה של קבוצה שאיבריה ידועים, כך שנתן לקרוא ולשחזר את הפרמוטציה.
|
דוגמה: נניח שהקבוצה היא |
כדוגמה למיון מבוסס-השוואות, נשתמש במיון הכנסה.
[עריכה] תהליך הכתיבה
תחילה מייצרים מערך בו כל איבר הוא זוג: הזוג ה
מורכב מהאיבר ה
בקבוצה, ומהמיקום
של איבר מקורי זה בפרמוטציה.
|
דוגמה: נניח שהקבוצה היא |
כעת לוקחים אלגוריתם מיון מבוסס-ההשוואות כלשהו (במקרה זה, Insertion-Sort), ומשנים אותו כך שהוא ממיין עפ"י השדה השני בכל זוג, ובכל פעם שהוא משווה, הוא מדפיס ביט המתאר את תוצאת ההשוואה:
Compare-And-Print(x, y) 1 if x > y 2 Print 1 3 return True 4 Print 0 5 return False Insertion-Sort-Zip(Values) 1 for i in [1, ..., Length(Values)] 2 v = Values[i] # Insert Values[j] into the correct position of Values[1, ..., j]. 3 j = i 4 while j > 1 and Compare-And-Print(Values[j - 1], v) 5 Values[j] = Values[j - 1] 6 --j 7 Values[j] = v
|
דוגמה: נניח שהמערך הוא |
|
שימו לב: מספר הביטים שהפונקציה מדפיסה עבור פרמוטציה כלשהי, הוא בדיוק מספר הפעמים בהם היא משווה איברים עבור אותה פרמוטציה. |
[עריכה] תהליך הקריאה
כדי לקרוא (ולשחזר) את הפרמוטציה, לוקחים מערך של איברי הקבוצה בסדר המקורי, ואת רצף הביטים שבקובץ.
|
דוגמה: נניח שהקבוצה היא |
כעת משנים את אותו אלגוריתם המיון (במקרה זה, Insertion-Sort) כך שכשהוא צריך להשוות בין שני איברים, הוא קורא ביט ומחליט מה לעשות. מריצים אלגורתים זה.
Read-And-Compare(x, y) 1 if Read() == 1 2 return True 3 return False Insertion-Sort-Unzip(Values) 1 for i in [1, ..., Length(Values)] 2 v = Values[i] # Insert Values[j] into the correct position of Values[1, ..., j]. 3 j = i 4 while j > 1 and Read-And-Compare(Values[j - 1], v) 5 Values[j] = Values[j - 1] 6 --j 7 Values[j] = v
מעצם הצורה שבה בנינו את שני האלגוריתמים, קל לראות את המשפט הבא:
|
משפט: תהליך הקריאה (והשחזור) אכן משחזר את הפרמוטציה המקורית. |
|
דוגמה: מתחילים עם המערך |
[עריכה] הוכחת החסם התחתון
כעת נוכל להוכיח את החסם התחתון על זמן הריצה של מיון מבוסס-השוואות.
הוכחה: נזכר בנקודות הבאות שכבר ראינו:
- כל אלגוריתם מיון מבוסס-השוואות יכול לשמש לכתיבת קובץ המתאר פרמוטציה של קבוצה שאיבריה ידועים, כך שנתן לקרוא ולשחזר את הפרמוטציה.
- מספר הביטים שהפונקציה מדפיסה עבור פרמוטציה כלשהי, הוא בדיוק מספר הפעמים בהם היא משווה איברים עבור אותה פרמוטציה.
- אם אורך הקבוצה הוא
, ואורך הקובץ הארוך ביותר הוא
, אז
.
משילוב המשפטים הקודמים קל לראות שלכל אלגוריתם מיון מבוסס-השוואות, קיימת פרמוטציה לה נדרשות
פעולות השוואה כדי למיינה. היות שכל פעולת השוואה היא
, אז זמן הריצה הוא
.
| הפרק הקודם: Quicksort |
החסם התחתון על מיון מבוסס-השוואות | הפרק הבא: אלגוריתמים למיון בזמן לינארי |
ל
מעלות (כלומר, יש 101 אפשרויות). רוצים לשמור, מדי יום, קובץ המתאר את הטמפרטורה באותו היום. נוכיח שלא ייתכן שבכל יום משתמשים בקובץ שארכו לכל היותר 2 ביטים.
קבצים כאלה, ו
.
.
קבצי קלט שונים, ויש
, ונקבל את התוצאה המבוקשת (לאחר מעט פישוטים לא קשים).
. פרמוטציה של
. אז הסידור
(קוקו ראשון, מנש שני, נחמה אחרונה) הוא פרמוטציה של הקבוצה, וכן הסידור
(מנש ראשון, קוקו שני, נחמה אחרונה) הוא פרמוטציה של הקבוצה (יש גם פרמוטציות אחרות).