🛤️ 10.5: Dijkstra Algoritması

Ağırlıklı Graflarda En Kısa Yol Bulma

📌 Dijkstra Algoritması Nedir?

Dijkstra Algoritması, Edsger W. Dijkstra tarafından 1956'da geliştirilen, ağırlıklı graflarda bir başlangıç noktasından diğer tüm noktalara en kısa yolu bulan bir algoritmadır.

🗺️ Navigasyon Uygulaması

Google Maps, Waze gibi navigasyon uygulamaları Dijkstra ve türevlerini kullanır:

  • Düğümler = Kavşaklar, şehirler
  • Kenarlar = Yollar
  • Ağırlıklar = Mesafe, süre, trafik durumu
🎯

Greedy Yaklaşım

Her adımda en iyi seçimi yapar

📊

Priority Queue

Min-heap ile verimli seçim

⚠️

Pozitif Ağırlık

Negatif kenarlarla çalışmaz

⚙️ Algoritma Adımları

1
Başlangıç: Başlangıç düğümünün mesafesini 0, diğerlerini ∞ olarak ayarla.
2
Seçim: İşlenmemiş düğümler arasından en küçük mesafeye sahip olanı seç.
3
Güncelleme: Seçilen düğümün tüm komşularını kontrol et. Eğer yeni yol daha kısaysa, mesafeyi güncelle.
if dist[u] + weight(u,v) < dist[v]:
    dist[v] = dist[u] + weight(u,v)
4
Tekrar: Tüm düğümler işlenene kadar adım 2-3'ü tekrarla.

🎮 İnteraktif Dijkstra Animasyonu

Dijkstra Adım Adım

Başlangıç: A | Hedef: Tüm düğümlere en kısa yol

🎯 "Başlat" butonuna basarak Dijkstra algoritmasını izleyin!

📋 Mesafe Tablosu

Düğüm A B C D E F
Mesafe 0

🎯 Priority Queue

Boş

🐍 Python Implementasyonu

Dijkstra - Temel Implementasyon
import heapq

def dijkstra(graph, start):
    """
    Dijkstra Algoritması - Priority Queue (Min-Heap) ile
    
    Args:
        graph: {node: [(neighbor, weight), ...], ...}
        start: Başlangıç düğümü
    
    Returns:
        distances: Her düğüme en kısa mesafe
        previous: Yol yeniden oluşturmak için önceki düğümler
    """
    # Başlangıç mesafeleri: başlangıç 0, diğerleri sonsuz
    distances = {node: float('infinity') for node in graph}
    distances[start] = 0
    
    # Yolu yeniden oluşturmak için
    previous = {node: None for node in graph}
    
    # Priority queue: (mesafe, düğüm)
    pq = [(0, start)]
    visited = set()
    
    while pq:
        current_dist, current = heapq.heappop(pq)
        
        # Bu düğümü zaten daha iyi bir yolla işledik mi?
        if current in visited:
            continue
            
        visited.add(current)
        print(f"İşlenen: {current} (mesafe: {current_dist})")
        
        # Komşuları kontrol et
        for neighbor, weight in graph[current]:
            if neighbor in visited:
                continue
                
            new_dist = current_dist + weight
            
            # Daha kısa bir yol bulduk mu?
            if new_dist < distances[neighbor]:
                distances[neighbor] = new_dist
                previous[neighbor] = current
                heapq.heappush(pq, (new_dist, neighbor))
                print(f"  → {neighbor} güncellendi: {new_dist}")
    
    return distances, previous


# Graf örneği (ağırlıklı kenarlar)
graph = {
    'A': [('B', 4), ('C', 2)],
    'B': [('A', 4), ('C', 1), ('D', 5)],
    'C': [('A', 2), ('B', 1), ('D', 8), ('E', 10)],
    'D': [('B', 5), ('C', 8), ('E', 2), ('F', 6)],
    'E': [('C', 10), ('D', 2), ('F', 3)],
    'F': [('D', 6), ('E', 3)]
}

print("=== GRAF (ağırlıklı) ===")
for node, edges in graph.items():
    print(f"  {node}: {edges}")

print("\n=== DIJKSTRA - A'dan tüm düğümlere ===\n")
distances, previous = dijkstra(graph, 'A')

print("\n=== SONUÇLAR ===")
print("\nEn kısa mesafeler:")
for node, dist in sorted(distances.items()):
    print(f"  A → {node}: {dist}")
Çıktı bekleniyor...
Dijkstra - Yol Yeniden Oluşturma
import heapq

def dijkstra_with_path(graph, start, end):
    """
    Dijkstra - Belirli bir hedefe en kısa yol
    
    Returns:
        distance: En kısa mesafe
        path: Yol listesi
    """
    distances = {node: float('infinity') for node in graph}
    distances[start] = 0
    previous = {node: None for node in graph}
    
    pq = [(0, start)]
    visited = set()
    
    while pq:
        current_dist, current = heapq.heappop(pq)
        
        if current == end:
            break  # Hedefe ulaştık!
            
        if current in visited:
            continue
            
        visited.add(current)
        
        for neighbor, weight in graph[current]:
            if neighbor not in visited:
                new_dist = current_dist + weight
                if new_dist < distances[neighbor]:
                    distances[neighbor] = new_dist
                    previous[neighbor] = current
                    heapq.heappush(pq, (new_dist, neighbor))
    
    # Yolu yeniden oluştur
    path = []
    current = end
    while current is not None:
        path.append(current)
        current = previous[current]
    path.reverse()
    
    return distances[end], path


# Graf
graph = {
    'A': [('B', 4), ('C', 2)],
    'B': [('A', 4), ('C', 1), ('D', 5)],
    'C': [('A', 2), ('B', 1), ('D', 8), ('E', 10)],
    'D': [('B', 5), ('C', 8), ('E', 2), ('F', 6)],
    'E': [('C', 10), ('D', 2), ('F', 3)],
    'F': [('D', 6), ('E', 3)]
}

print("=== GRAF ===")
print("       4")
print("   A------B")
print("   |\\     |\\")
print("   | \\2   |1\\ 5")
print("   |  \\   |  \\")
print("   |   C--+---D")
print("   |  10\\ |8  |\\")
print("   |     \\|   |2\\ 6")
print("   |      E---+--F")
print("           3")

print("\n=== A'DAN HER DÜĞÜME EN KISA YOL ===\n")

for target in ['B', 'C', 'D', 'E', 'F']:
    dist, path = dijkstra_with_path(graph, 'A', target)
    path_str = ' → '.join(path)
    print(f"A → {target}: mesafe={dist}, yol: {path_str}")
Çıktı bekleniyor...

📊 Karmaşıklık Analizi

Implementasyon Zaman Not
Array (Naif) O(V²) Her seferinde minimum arama
Binary Heap O((V+E) log V) Python heapq, çoğu durumda ideal
Fibonacci Heap O(V log V + E) Teorik en iyi, pratikte karmaşık

💡 Pratikte

  • Yoğun graf (E ≈ V²): Array versiyonu O(V²) yeterli olabilir
  • Seyrek graf (E ≈ V): Binary Heap tercih edilir → O(V log V)
  • Python: heapq modülü binary heap sağlar, çoğu durumda yeterli

⚠️ Dijkstra'nın Sınırlamaları

🚫 Negatif Ağırlıklar

Dijkstra algoritması negatif ağırlıklı kenarlarla çalışmaz!

Neden? Çünkü algoritma "greedy" yaklaşımla çalışır ve bir düğümü işledikten sonra tekrar ziyaret etmez. Negatif kenarlar daha kısa yollar oluşturabilir.

Negatif Ağırlık Problemi
import heapq

def dijkstra_basic(graph, start, end):
    distances = {node: float('infinity') for node in graph}
    distances[start] = 0
    pq = [(0, start)]
    visited = set()
    
    while pq:
        current_dist, current = heapq.heappop(pq)
        if current in visited:
            continue
        visited.add(current)
        
        if current == end:
            break
            
        for neighbor, weight in graph[current]:
            if neighbor not in visited:
                new_dist = current_dist + weight
                if new_dist < distances[neighbor]:
                    distances[neighbor] = new_dist
                    heapq.heappush(pq, (new_dist, neighbor))
    
    return distances[end]


# Negatif ağırlıklı graf
graph_negative = {
    'A': [('B', 1), ('C', 4)],
    'B': [('C', -3)],  # ⚠️ Negatif kenar!
    'C': []
}

print("=== NEGATİF AĞIRLIKLI GRAF ===")
print("    1      -3")
print("A ----→ B ----→ C")
print("  \\           ↗")
print("   \\----→----/")
print("       4")
print()

# Dijkstra sonucu (yanlış olabilir!)
result = dijkstra_basic(graph_negative, 'A', 'C')
print(f"Dijkstra sonucu A→C: {result}")

# Doğru cevap
print(f"Doğru cevap: A→B→C = 1 + (-3) = -2")

if result != -2:
    print("\n⚠️ Dijkstra yanlış sonuç verdi!")
    print("Negatif ağırlıklar için Bellman-Ford kullanın.")
Çıktı bekleniyor...

🆚 En Kısa Yol Algoritmaları Karşılaştırması

Dijkstra

  • Tek kaynak, tüm hedefler
  • Sadece pozitif ağırlıklar
  • O(V log V + E) binary heap ile
  • En yaygın kullanılan

Bellman-Ford

  • Tek kaynak, tüm hedefler
  • Negatif ağırlıkları destekler
  • O(V × E)
  • Negatif döngü tespiti yapabilir

Floyd-Warshall

  • Tüm çiftler arası en kısa yol
  • Negatif ağırlıkları destekler
  • O(V³)
  • Yoğun graflar için ideal
Özellik Dijkstra Bellman-Ford Floyd-Warshall
Kaynak Tek Tek Tümü
Negatif kenar
Negatif döngü tespiti
Zaman O((V+E)logV) O(VE) O(V³)

🌍 Gerçek Dünya Uygulamaları

🗺️ Navigasyon Sistemleri

Google Maps, Waze - en kısa/hızlı rota bulma

🌐 Ağ Yönlendirme

OSPF protokolü - paket routing, IP ağları

🎮 Oyun AI

Pathfinding - karakterlerin hareket planlaması

🤖 Robotik

Otonom araçlar, robot navigasyonu