Menu
Coddy logo textTech

האלגוריתם של Kruskal (קרוסקל)

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

האלגוריתם של Kruskal בונה עץ פורש מינימלי (MST): קבוצת הקשתות הזולה ביותר שמחברת את כל הצמתים בלי מעגלים. הוא ממיין את כל הקשתות לפי משקל, ואז מוסיף בצורה חמדנית את הקשת הזולה הבאה, כל עוד היא מחברת שני צמתים שעוד לא מחוברים. לחצו על הפעלה למעלה כדי לראות את העץ גדל, קשת בטוחה וזולה אחת בכל פעם.

הבדיקה "האם כבר מחוברים?" מתבצעת בעזרת מבנה הנתונים union-find (קבוצות זרות): מדלגים על קשת אם שני הקצוות שלה כבר באותו רכיב, כי הוספה שלה הייתה יוצרת מעגל. המיון שולט בעלות, ונותן O(E log E) בסך הכל. Kruskal מצטיין בגרפים דלילים.

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

מדדסיבוכיותהערות
זמןO(E log E)נשלט על ידי מיון הקשתות
פעולות union-find≈ O(E α(V))כמעט קבוע לכל בדיקה עם כיווץ מסלולים
זיכרוןO(V + E)רשימת קשתות ומבנה קבוצות זרות
הכי מתאים לגרפים דליליםעובד מרשימת קשתות גלובלית

צעד אחר צעד

צעדמה קורה
1ממיינים את כל הקשתות לפי משקל, בסדר עולה.
2מכניסים כל צומת לרכיב משלו (union-find).
3לוקחים את הקשת הזולה הבאה.
4אם הקצוות שלה ברכיבים שונים, מוסיפים אותה לעץ ומאחדים אותם.
5אחרת מדלגים עליה (היא הייתה יוצרת מעגל).
6עוצרים כשבעץ יש V − 1 קשתות.

דוגמה מפורטת

גרף עם הצמתים A, B, C, D והקשתות A-B(1), B-C(2), A-C(3), C-D(4), B-D(5). הקשתות הממוינות: A-B(1), B-C(2), A-C(3), C-D(4), B-D(5):

קשת (משקל)רכיבים לפניפעולה
A-B(1){A} {B} {C} {D}רכיבים שונים: מוסיפים ל-MST ומאחדים ל-{A,B}.
B-C(2){A,B} {C} {D}רכיבים שונים: מוסיפים ל-MST ומאחדים ל-{A,B,C}.
A-C(3){A,B,C} {D}A ו-C כבר יחד: מדלגים (היה נוצר מעגל).
C-D(4){A,B,C} {D}רכיבים שונים: מוסיפים ל-MST ומאחדים ל-{A,B,C,D}.
עצירה{A,B,C,D}בעץ יש V - 1 = 3 קשתות. MST = A-B, B-C, C-D, משקל כולל 7.

מתי להשתמש באלגוריתם של Kruskal

השתמשו בו כאשרהימנעו ממנו כאשר
הגרף דליל (מעט קשתות ביחס לצמתים).הגרף צפוף: Prim עם ערימה בדרך כלל מהיר יותר.
הקשתות כבר זמינות כרשימה גלובלית שאפשר למיין.הקשתות מגיעות רק דרך רשימות סמיכות שצריך לסרוק לכל צומת.
אתם רוצים מימוש פשוט שנשען על union-find.אתם צריכים שהעץ יגדל מצומת התחלה מסוים.
אתם רוצים לבנות יער פורש של גרף לא קשיר.אתם חייבים לטפל בקשתות שמגיעות בזרם בלי מיון מלא.

קוד Kruskal's Algorithm

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

קוד Kruskal's Algorithm ב-Python

Python
1def find(parent, x):2    while parent[x] != x:3        parent[x] = parent[parent[x]]  # path compression4        x = parent[x]5    return x6
7
8def kruskal(vertices, edges):9    # Take the cheapest edge that does not close a cycle10    parent = {v: v for v in vertices}11    mst, total = [], 012    for w, u, v in sorted(edges):13        root_u, root_v = find(parent, u), find(parent, v)14        if root_u != root_v:15            parent[root_u] = root_v16            mst.append((u, v, w))17            total += w18    return mst, total19
20
21vertices = ["A", "B", "C", "D", "E"]22edges = [23    (4, "A", "B"), (1, "A", "C"), (3, "B", "C"), (2, "B", "D"),24    (5, "C", "D"), (6, "C", "E"), (7, "D", "E"),25]26
27mst, total = kruskal(vertices, edges)28for u, v, w in mst:29    print(f"{u} - {v} (weight {w})")30print("Total MST weight:", total)
להריץ את הקוד הזה בעורך ה-Python אונליין

שאלות נפוצות על האלגוריתם של Kruskal

מהו עץ פורש מינימלי?
עץ פורש מינימלי (MST) של גרף ממושקל קשיר הוא תת קבוצה של קשתות שמחברת את כל הצמתים בלי מעגלים ועם המשקל הכולל הקטן ביותר האפשרי. יש בו בדיוק V - 1 קשתות עבור V צמתים.
מה ההבדל בין האלגוריתם של Kruskal לאלגוריתם של Prim?
שניהם בונים עץ פורש מינימלי בצורה חמדנית. Kruskal ממיין את כל הקשתות באופן גלובלי ומוסיף את הזולה ביותר שלא יוצרת מעגל, בעזרת union-find. Prim מגדל עץ יחיד החוצה מצומת התחלה, ותמיד מוסיף את הקשת הזולה ביותר שיוצאת מהעץ. Kruskal מתאים לגרפים דלילים; Prim (עם ערימה) מתאים לגרפים צפופים.
למה האלגוריתם של Kruskal משתמש ב-union-find?
לפני הוספת קשת, Kruskal חייב לבדוק אם שני הקצוות שלה כבר מחוברים, כי הוספת קשת כזו הייתה יוצרת מעגל. Union-find (קבוצות זרות) עונה על השאלה "האם הם באותו רכיב?" ומאחד רכיבים בזמן כמעט קבוע לשיעורין, וזה שומר על יעילות האלגוריתם.
מתי כדאי להשתמש באלגוריתם של Kruskal במקום באלגוריתם של Prim?
העדיפו את Kruskal כשהגרף דליל וכבר יש לכם את כל הקשתות כרשימה שאפשר למיין: המיון של O(E log E) זול כש-E קטן. האלגוריתם של Prim עם ערימה בינארית או ערימת פיבונאצ'י נוטה לנצח בגרפים צפופים שבהם E מתקרב ל-V², כי הוא נמנע ממיון של כל הקשתות מראש.
האם האלגוריתם של Kruskal עובד על גרפים לא קשירים?
כן. אם הגרף לא קשיר, Kruskal פשוט לא יכול להגיע ל-V - 1 קשתות, ובמקום זאת מייצר יער פורש מינימלי: MST אחד לכל רכיב קשירות. זה קורה באופן טבעי, כי union-find לעולם לא מאחד צמתים שאין ביניהם מסלול.
מהי הטעות הנפוצה ביותר במימוש האלגוריתם של Kruskal?
ויתור על כיווץ המסלולים ועל האיחוד לפי דרגה ב-union-find, מה שמוריד כל בדיקת קישוריות מזמן כמעט קבוע לזמן כמעט ליניארי ועלול לשלוט בזמן הריצה. באג נפוץ נוסף הוא לשכוח לאחד בפועל את שני הרכיבים אחרי הוספת קשת, מה שמאפשר לקשתות מאוחרות יותר ליצור מעגלים.
איור של שפות התכנות ב-Coddy

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

להתחיל