Menu
Coddy logo textTech

האלגוריתם של Prim (פרים)

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

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

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

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

מימושסיבוכיותהערות
ערימה בינאריתO(E log V)תור עדיפויות של קשתות חוצות
מטריצת סמיכותO(V²)פשוט יותר; טוב לגרפים צפופים
זיכרוןO(V + E)שייכות לעץ ותור עדיפויות
הכי מתאים לגרפים צפופיםגדל מצומת התחלה יחיד

צעד אחר צעד

צעדמה קורה
1מתחילים את העץ עם צומת יחיד כלשהו.
2בודקים את כל הקשתות שחוצות מהעץ לצומת שמחוצה לו.
3בוחרים את הקשת החוצה עם המשקל הקטן ביותר.
4מוסיפים לעץ את הקשת הזו ואת הצומת החדש שלה.
5חוזרים על כך עד שכל הצמתים בעץ.

דוגמה מפורטת

בניית ה-MST של גרף עם 4 צמתים והקשתות A-B=1, A-C=3, B-C=2, B-D=4, C-D=5, החל מ-A:

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

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

השתמשו בו כאשרהימנעו ממנו כאשר
אתם צריכים עץ פורש מינימלי של גרף ממושקל, קשיר ולא מכוון.הגרף מכוון או שאתם צריכים מסלולים קצרים ביותר: השתמשו במקום זאת ב-Dijkstra או ב-Bellman-Ford.
הגרף צפוף (E קרוב ל-V²); צורת המטריצה של O(V²) פשוטה ומהירה.הגרף דליל והקשתות כבר ממוינות או קלות למיון: Kruskal לעתים קרובות פשוט יותר.
אתם רוצים שהעץ יגדל מאזור אחד החוצה (למשל פריסת רשת הדרגתית).הגרף לא קשיר: Prim פורש רק רכיב אחד; אתם צריכים יער פורש מינימלי.
כבר יש לכם מבנה סמיכות ותור עדיפויות זמינים.אתם צריכים לזהות מעגלים על פני קבוצת קשתות גלובלית: union-find (Kruskal) מתאים לזה יותר.

קוד Prim's Algorithm

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

קוד Prim's Algorithm ב-Python

Python
1import heapq2
3
4def prim(graph, start):5    visited = {start}6    heap = [(w, start, v) for v, w in graph[start]]7    heapq.heapify(heap)8    mst, total = [], 09    while heap and len(visited) < len(graph):10        w, u, v = heapq.heappop(heap)11        if v in visited:12            continue13        visited.add(v)14        mst.append((u, v, w))15        total += w16        # Offer the new node's edges to the frontier17        for neighbor, weight in graph[v]:18            if neighbor not in visited:19                heapq.heappush(heap, (weight, v, neighbor))20    return mst, total21
22
23graph = {24    "A": [("B", 4), ("C", 1)],25    "B": [("A", 4), ("C", 3), ("D", 2)],26    "C": [("A", 1), ("B", 3), ("D", 5)],27    "D": [("B", 2), ("C", 5), ("E", 7)],28    "E": [("D", 7)],29}30
31mst, total = prim(graph, "A")32for u, v, w in mst:33    print(f"{u} - {v} (weight {w})")34print("Total MST weight:", total)
להריץ את הקוד הזה בעורך ה-Python אונליין

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

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

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

להתחיל