Menu
Coddy logo textTech

האלגוריתם של Dijkstra (דייקסטרה)

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

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

התובנה המרכזית היא חמדנית: ברגע שנבחר הצומת הלא סופי הקרוב ביותר, המרחק שלו סופי, כי כל מסלול אחר אליו היה צריך לעבור דרך צומת שכבר רחוק יותר. עם תור עדיפויות מבוסס ערימה בינארית, Dijkstra רץ בזמן O((V + E) log V). הוא דורש משקלים אי שליליים: השתמשו ב-Bellman-Ford אם קשתות יכולות להיות שליליות.

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

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

צעד אחר צעד

צעדמה קורה
1קובעים את מרחק המקור ל-0 ואת כל השאר לאינסוף.
2בוחרים את הצומת הלא סופי עם המרחק הזמני הקטן ביותר.
3מסמנים אותו כסופי: המרחק הקצר ביותר שלו נקבע סופית.
4לכל שכן, מחשבים את המרחק דרך הצומת הנוכחי ועוד משקל הקשת.
5אם הוא קטן מהמרחק הנוכחי של השכן, מרככים אותו.
6חוזרים על כך עד שכל הצמתים הנגישים סופיים.

דוגמה מפורטת

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

צעדקביעהמרחקיםפעולה
0-A=0, B=∞, C=∞, D=∞אתחול: המקור A=0, כל השאר אינסוף.
1A (0)B=4, C=1, D=∞מרככים את הקשתות מ-A: B=4, C=1.
2C (1)B=3, D=6דרך C: B=1+2=3 עדיף על 4; D=1+5=6.
3B (3)D=4דרך B: D=3+1=4 עדיף על 6.
4D (4)A=0, C=1, B=3, D=4קובעים את D; לא נשאר מה לרכך. סיום.

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

השתמשו בו כאשרהימנעו ממנו כאשר
כל משקלי הקשתות אי שלילייםקשת כלשהי יכולה להיות שלילית: השתמשו ב-Bellman-Ford
אתם צריכים מסלולים קצרים ביותר ממקור אחד לכל הצמתיםאתם צריכים מסלולים קצרים ביותר בין כל הזוגות: Floyd-Warshall פשוט יותר
הגרף ממושקל ואתם רוצים מרחקים מדויקיםהגרף לא ממושקל: BFS רגיל מהיר ופשוט יותר
יש לכם ערימה או תור עדיפויות טוביםאתם רוצים להגיע מהר ליעד יחיד בעזרת היוריסטיקה: השתמשו ב-A*

קוד Dijkstra's Algorithm

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

קוד Dijkstra's Algorithm ב-Python

Python
1import heapq2
3
4def dijkstra(graph, start):5    dist = {node: float("inf") for node in graph}6    dist[start] = 07    pq = [(0, start)]8    while pq:9        d, node = heapq.heappop(pq)10        if d > dist[node]:11            continue  # stale entry, a shorter path was already found12        for neighbor, weight in graph[node]:13            new_dist = d + weight14            if new_dist < dist[neighbor]:15                dist[neighbor] = new_dist16                heapq.heappush(pq, (new_dist, neighbor))17    return dist18
19
20graph = {21    "A": [("B", 4), ("C", 1)],22    "B": [("D", 1)],23    "C": [("B", 2), ("D", 5)],24    "D": [("E", 3)],25    "E": [],26}27
28for node, d in dijkstra(graph, "A").items():29    print(f"A -> {node}: {d}")
להריץ את הקוד הזה בעורך ה-Python אונליין

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

מהי סיבוכיות הזמן של האלגוריתם של Dijkstra?
עם תור עדיפויות מבוסס ערימה בינארית הוא רץ ב-O((V + E) log V). גרסה פשוטה שסורקת מערך כדי למצוא את המינימום בכל צעד היא O(V²), והיא יכולה להיות דווקא מהירה יותר בגרפים צפופים. שתיהן משתמשות ב-O(V) זיכרון.
למה Dijkstra לא עובד עם משקלי קשתות שליליים?
Dijkstra מניח שברגע שהוא קובע את הצומת הלא סופי הקרוב ביותר, המרחק הזה סופי. קשת שלילית יכולה ליצור מאוחר יותר מסלול קצר יותר לצומת שכבר נקבע, וזה שובר את ההנחה. בגרפים עם משקלים שליליים השתמשו באלגוריתם Bellman-Ford.
מה ההבדל בין Dijkstra ל-BFS?
BFS מוצא מסלולים קצרים ביותר לפי מספר קשתות (בפועל, המשקל של כל קשת הוא 1), בעזרת תור רגיל. Dijkstra מכליל את זה לגרפים ממושקלים על ידי הרחבה תמידית של הצומת עם המרחק הכולל הקטן ביותר, בעזרת תור עדיפויות. בגרף לא ממושקל שניהם מחזירים את אותם מסלולים.
מה ההבדל בין Dijkstra לחיפוש A*?
A* הוא Dijkstra בתוספת היוריסטיקה שמעריכה את המרחק שנותר ליעד, כך שהוא מכוון את החיפוש לעבר המטרה במקום להתרחב באופן שווה לכל הכיוונים. כשההיוריסטיקה היא אפס, A* הופך בדיוק ל-Dijkstra. השתמשו ב-A* כשיש יעד יחיד והיוריסטיקה קבילה טובה; השתמשו ב-Dijkstra כשצריך מרחקים לכל הצמתים.
מתי כדאי להשתמש ב-Dijkstra במקום ב-Bellman-Ford?
השתמשו ב-Dijkstra בכל פעם שכל משקלי הקשתות אי שליליים: הוא מהיר יותר, O((V + E) log V) לעומת O(V·E) של Bellman-Ford. בחרו ב-Bellman-Ford רק כשקשתות יכולות להיות שליליות או כשצריך לזהות מעגלים שליליים. בגרפים אי שליליים Dijkstra הוא כמעט תמיד הבחירה הטובה יותר.
האם Dijkstra יכול לחזור לצומת אחרי שהוא נקבע?
לא. ברגע שצומת נקבע, המרחק שלו סופי והוא לעולם לא מרוכך שוב. מלכודת נפוצה במימושים עם ערימה היא להשאיר רשומות מיושנות בתור העדיפויות אחרי שהמרחק של צומת משתפר; צריך לדלג על צומת שנשלף אם הוא כבר נקבע (המרחק שנשלף גדול מהמרחק הרשום שלו). שכחה של הבדיקה הזו עדיין נותנת תשובות נכונות, אבל מבזבזת עבודה.
איור של שפות התכנות ב-Coddy

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

להתחיל