Dijkstra Algoritması
Negatif olmayan ağırlıklı bir grafta başlangıçtan tüm düğümlere en ucuz yolları bulan açgözlü algoritma.
Önce bunlara göz at
#Nasıl çalışır?
Dijkstra algoritması (Edsger Dijkstra, 1956), kenarları negatif olmayan ağırlıklara sahip bir grafta, bir başlangıç düğümünden diğer tüm düğümlere en kısa (en ucuz) yolları bulur.
BFS kenar sayısını en aza indirir; ama kenarların uzunlukları, süreleri ya da maliyetleri farklıysa en az kenarlı yol en ucuz yol olmayabilir. Örnek grafta BFS'in bulduğu 1 → 2 → 4 → 7 yolu 12'ye, Dijkstra'nın bulduğu 1 → 3 → 6 → 7 yolu 6'ya mal oluyor.
Algoritma açgözlüdür (greedy): her adımda henüz kesinleşmemiş düğümler içinde mesafesi en küçük olanı seçer ve kesinleştirir. Ağırlıklar negatif olmadığı için o düğüme daha sonra daha kısa bir yoldan ulaşmak imkânsızdır.
Kesinleşen düğümün komşuları "gevşetilir" (relaxation): dist[u] + w, dist[v]'den küçükse dist[v] güncellenir ve prev[v] = u yazılır. En küçük mesafeli düğümü hızlıca bulmak için öncelik kuyruğu (min-heap) kullanılır.
#Kendin dene
Komşuluk listesi
- 1: 2 (4), 3 (1)
- 2: 1 (4), 4 (5), 5 (2)
- 3: 1 (1), 5 (2), 6 (4)
- 4: 2 (5), 7 (3)
- 5: 2 (2), 3 (2), 7 (6)
- 6: 3 (4), 7 (1)
- 7: 4 (3), 5 (6), 6 (1)
Kenarların üstündeki sayılar ağırlıklardır. Dijkstra her adımda kuyruktaki en küçük mesafeli düğümü kesinleştirir. BFS yolu ile en ucuz yolu karşılaştır.
#Adım adım
- 01dist[başlangıç] = 0, diğer tüm mesafeler ∞; başlangıcı öncelik kuyruğuna koy.
- 02Kuyruktan mesafesi en küçük düğümü (u) al ve kesinleştir.
- 03u'nun kesinleşmemiş her komşusu v için: dist[u] + w(u, v) < dist[v] ise dist[v]'yi güncelle, prev[v] = u yaz ve v'yi kuyruğa ekle.
- 04Kuyruk boşalana (ya da hedef kesinleşene) kadar tekrarla; yolu prev[] zincirini hedeften geriye izleyerek çıkar.
#Örnek kod
Aynı algoritma 8 dilde. Her program derlenip çalıştırılarak test edildi ve hepsi aynı çıktıyı veriyor.
import heapq
# Undirected weighted graph: graph[u] = [(v, weight), ...]
EDGES = [(1, 2, 4), (1, 3, 1), (2, 4, 5), (2, 5, 2), (3, 5, 2), (3, 6, 4), (4, 7, 3), (5, 7, 6), (6, 7, 1)]
graph = {v: [] for v in range(1, 8)}
for a, b, w in EDGES:
graph[a].append((b, w))
graph[b].append((a, w))
def dijkstra(start: int):
dist = {v: float("inf") for v in graph}
prev = {}
dist[start] = 0
heap = [(0, start)] # (distance, node), smallest first
while heap:
d, u = heapq.heappop(heap)
if d > dist[u]:
continue # an outdated entry: u was already settled with a smaller distance
for v, w in graph[u]:
if d + w < dist[v]:
dist[v] = d + w
prev[v] = u
heapq.heappush(heap, (dist[v], v))
return dist, prev
dist, prev = dijkstra(1)
print(" ".join(str(dist[v]) for v in range(1, 8))) # distance from 1 to nodes 1..7
path = [7]
while path[-1] != 1:
path.append(prev[path[-1]])
print(" ".join(map(str, reversed(path)))) # cheapest path, not the fewest edges (1 2 4 7)
print(dist[7])#Karmaşıklık
| İşlem | Süre |
|---|---|
| İkili heap ile | O((V + E) log V) |
| Dizi ile (heap yok) | O(V²) |
| Fibonacci heap ile | O(E + V log V) |
| Bellek | O(V) |
Her kenar en fazla bir kez gevşetilir ve her gevşetme heap'e O(log V) maliyetle bir ekleme yapabilir. Yoğun graflarda (E ≈ V²) basit dizi sürümü daha hızlı olabilir. Negatif ağırlıklı kenar varsa Dijkstra yanlış sonuç verir; o zaman Bellman-Ford kullanılır.
#Ne zaman kullanılır?
Harita ve navigasyon uygulamalarında rota bulma, ağ yönlendirme protokolleri (OSPF), oyunlarda yol bulma (A* algoritması Dijkstra'nın sezgisel bir uzantısıdır), uçuş ve toplu taşıma planlaması gibi tüm "en ucuz/en hızlı rota" problemleri Dijkstra ile çözülür.
#Alıştırma
Soruları cevaplamak ve ilerlemeni kaydetmek için giriş yap.
Kolay
Dijkstra her adımda hangi düğümü kesinleştirir?
- 1Kesinleşmemişler içinde mesafesi en küçük olanı
- 2Başlangıca en az kenarla bağlı olanı
- 3En çok komşusu olanı
- 4Rastgele bir düğümü
Dijkstra hangi durumda yanlış sonuç verebilir?
- 1Negatif ağırlıklı kenar olduğunda
- 2Graf yönsüz olduğunda
- 3Ağırlıklar ondalıklı olduğunda
- 4Graf çok büyük olduğunda
Dijkstra'da en küçük mesafeli düğümü hızlıca bulmak için hangi yapı kullanılır?
- 1Öncelik kuyruğu (min-heap)
- 2Yığın (stack)
- 3Sıradan kuyruk (FIFO)
- 4Hash tablosu
Orta
dist[u] = 3, u–v kenarının ağırlığı 2 ve dist[v] = 7 ise gevşetme (relaxation) sonrası dist[v] kaç olur?
- 15
- 27
- 32
- 49
Zor
İkili heap ile Dijkstra'nın zaman karmaşıklığı nedir?
- 1O((V + E) log V)
- 2O(V + E)
- 3O(V · E)
- 4O(E²)
#Bundan sonra
Bu dersi bildiğini varsayan dersler: