İçeriğe geç

Menü

Berk Akademi
Yorumlar Google yorumları Birebir ders başvurusu Ücretsiz ön görüşme Ana Sayfa

Dijkstra Algoritması Nasıl Çalışır? En Kısa Yol Örneği

dijkstra-algoritmasi-nasil-calisir
Bu yazıda neler var?
  1. Dijkstra algoritması her turda ne yapar?
  2. Beş düğümlü grafikte Dijkstra'yı elle çözmek
  3. En kısa yolu önceki düğümlerden sondan başa kurmak
  4. Sözde kod ve heapq ile Python uygulaması
  5. Dijkstra negatif kenarlarda neden güvenilir değildir?
  6. Dijkstra ne zaman kullanılır, ne zaman kullanılmaz? Karmaşıklık ve karar çerçevesi
  7. Sık Sorulan Sorular

Dijkstra algoritması, negatif olmayan ağırlıklı bir grafikte başlangıç düğümünden diğer tüm düğümlere olan en kısa yolları bulur. Başlangıç düğümünden başlarsın, geçici uzaklığı en küçük olan düğümü seçersin ve komşularının uzaklıklarını güncellersin. Bunu tüm düğümler kesinleşene kadar sürdürürsün. Bu yazıda tek bir örnek grafiği tur tur elle çözerek en kısa yol mantığını göreceksin.

Dijkstra algoritması her turda ne yapar?

Dijkstra her turda en küçük geçici uzaklığa sahip düğümü kesinleştirir ve bu düğümün komşularını yeni bir yol üzerinden yeniden değerlendirir. Algoritmanın bütün işi bu iki hamlenin tekrarıdır: önce en umut verici düğümü seç, sonra onun üzerinden daha kısa bir yol çıkıp çıkmadığına bak.

Makale boyunca tek bir grafik kullanacağız: yönsüz, ağırlıklı, 5 düğümlü ve 7 kenarlı. Düğümler A, B, C, D ve E. Kenarlar ve ağırlıkları şöyle:

  • A-B: 4
  • A-C: 2
  • B-C: 1
  • B-D: 5
  • C-D: 8
  • C-E: 10
  • D-E: 2

Başlangıç düğümümüz A. Amacımız A'dan her düğüme giden en kısa yolun toplam ağırlığını bulmak. Kavramları bu örnek üzerinden tanımlayalım:

  • Düğüm: Grafikteki noktalar. Örneğimizde A, B, C, D ve E.
  • Kenar ve ağırlık: İki düğümü bağlayan çizgi ve üzerindeki maliyet. A-C kenarının ağırlığı 2'dir.
  • Başlangıç uzaklığı: Başlangıç düğümünün kendisine uzaklığı sıfırdır, yani A için 0.
  • Geçici uzaklık: Bir düğüme şimdiye kadar bulunmuş en kısa yolun uzunluğu. Başta A dışındaki tüm düğümler için sonsuzdur, çünkü henüz hiçbirine yol bulmadık.
  • Seçilmiş (kesinleşmiş) düğüm: Uzaklığı artık değişmeyecek olan düğüm. Her tur tam bir düğüm bu duruma geçer.
  • Önceki düğüm: Bir düğüme şimdiki en iyi yolla hangi düğümden gelindiği. Yolu sonradan geriye doğru kurmak için bu bilgiyi saklarız.

Kısacası her düğümün iki bilgisi vardır: geçici uzaklığı ve önceki düğümü. Algoritma ilerledikçe bu iki bilgi güncellenir, düğümler tek tek kesinleşir.

Beş düğümlü grafikte Dijkstra'yı elle çözmek

Beş düğümlü grafikte Dijkstra'yı elle çözmek

Aşağıdaki tabloda her satır bir turu gösteriyor. Hücrelerde geçici uzaklık ve parantez içinde önceki düğüm yer alır; kesinleşen düğümün değeri kalın yazılmıştır.

TurSeçilen düğümABCDE
Başlangıç-0∞∞∞∞
1A04 (A)2 (A)∞∞
2C03 (C)2 (A)10 (C)12 (C)
3B03 (C)2 (A)8 (B)12 (C)
4D03 (C)2 (A)8 (B)10 (D)
5E03 (C)2 (A)8 (B)10 (D)

Final uzaklıklar: A=0, B=3, C=2, D=8, E=10.

Gevşetme adımı: B'nin değeri neden düştü?

Tablodaki asıl hareket 2. turda gerçekleşir. A-B kenarı doğrudan 4 ağırlığındaydı. Ancak C kesinleştiğinde A→C→B yolunun toplamı 2 + 1 = 3 çıkar ve bu, 4'ten küçüktür. B'nin değeri 3'e iner, önceki düğümü C olur. Bu güncellemeye gevşetme denir. Mantığı tek cümledir: seçilen düğümün uzaklığı + kenar ağırlığı, komşunun mevcut değerinden küçükse komşuyu güncelle. Aynı kural 3. turda D'yi 10'dan 8'e (3 + 5), 4. turda E'yi 12'den 10'a (8 + 2) indirir.

Bir düğüm seçildiği anda değerinin bir daha değişmemesinin nedeni şudur: seçilmemiş diğer tüm düğümlerin geçici uzaklığı seçilenden küçük olamaz. Ağırlıkların hiçbiri negatif olmadığı için, o düğümlerden birinin üzerinden geçen bir yol seçilen düğüme daha kısa bir rota sunamaz. Bu varsayım Dijkstra'nın doğruluğunun temelidir.

Sınavda tablo kurarken tek bir ipucu işini kolaylaştırır: her turda yalnızca seçilen düğümün komşularına bak. Kesinleşmiş düğümlere geri dönmen gerekmez. Elle çözümü kendi çizdiğin grafiklerde tekrarladıktan sonra, dilden bağımsız algoritmik düşünme becerini Algoritmik Düşünme Testi ile ölçebilirsin.

En kısa yolu önceki düğümlerden sondan başa kurmak

Mesafe tablosu yalnızca uzunluğu verir, yolun kendisini vermez. Yolu kurmak için her düğümün en kısa uzaklığına hangi düğümden gelindiğini de kaydedersin. Bu kayda önceki düğüm denir; bir düğümün uzaklığı her güncellendiğinde önceki düğümü de güncellenir.

Örnek grafikte E'nin önceki düğümü D, D'nin B, B'nin C, C'nin de A'dır. Hedeften başlayıp geriye doğru okursan E←D←B←C←A dizisini bulursun. Bunu ters çevirince yol A → C → B → D → E olur. Kenar ağırlıkları 2+1+5+2 = 10 eder ve bu, tablodaki E değeriyle aynıdır. Doğrudan A-C-E yolu 2+10 = 12 tuttuğu için daha uzundur.

Kısa bir kontrol önerisi: Kurduğun yoldaki kenar ağırlıklarını topla. Toplam tablodaki uzaklığa eşit çıkmıyorsa önceki düğüm kayıtlarında ya da güncelleme adımında bir hata var demektir.

Sözde kod ve heapq ile Python uygulaması

Sözde kod ve heapq ile Python uygulaması

Önce algoritmanın iskeleti. Kuyruk, (uzaklık, düğüm) çiftlerini küçükten büyüğe sıralı tutan bir öncelik kuyruğudur.

tüm düğümlerin uzaklığını sonsuz yap
başlangıcın uzaklığını 0 yap
kuyruğa (0, başlangıç) ekle
kuyruk boşalana kadar:
    (d, u) = kuyruktan en küçük çifti çek
    eğer d > uzaklık[u] ise: atla
    u'nun her komşusu v için (ağırlık w):
        yeni = d + w
        eğer yeni < uzaklık[v] ise:
            uzaklık[v] = yeni
            önceki[v] = u
            kuyruğa (yeni, v) ekle

Aynı grafiği Python'da heapq modülüyle çözelim. Grafik, ders tablosundakiyle birebir aynıdır; her kenar iki yönlü eklenmiştir.

import heapq

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},
    "E": {"C": 10, "D": 2},
}

def dijkstra(graph, start):
    dist = {node: float("inf") for node in graph}
    prev = {node: None for node in graph}
    dist[start] = 0
    queue = [(0, start)]
    while queue:
        d, u = heapq.heappop(queue)
        if d > dist[u]:
            continue
        for v, w in graph[u].items():
            yeni = d + w
            if yeni < dist[v]:
                dist[v] = yeni
                prev[v] = u
                heapq.heappush(queue, (yeni, v))
    return dist, prev

dist, prev = dijkstra(graph, "A")

yol = []
node = "E"
while node is not None:
    yol.append(node)
    node = prev[node]
yol.reverse()

print("Uzaklıklar:", dist)
print("En kısa yol:", " -> ".join(yol))
print("Toplam:", dist["E"])

Beklenen çıktı:

Uzaklıklar: {'A': 0, 'B': 3, 'C': 2, 'D': 8, 'E': 10}
En kısa yol: A -> C -> B -> D -> E
Toplam: 10

Değerler elle çözümdeki tabloyla, yol da önceki düğümlerden kurduğumuz diziyle aynıdır.

if d > dist[u]: continue satırı kuyruktaki eski kayıtları eler. Örnekte B önce 4 ile kuyruğa girer, sonra C üzerinden 3'e düşer ve kuyruğa ikinci kez eklenir. Kuyruktan önce (3, B) çıkar; sonradan gelen (4, B) kaydı güncel uzaklıktan büyük olduğu için atlanır. Bu satır olmasa sonuç yine doğru çıkardı ama gereksiz tekrar işlem yapılırdı.

Kodu kendi başına yeniden yazıp değiştirdikten sonra düzeyini görmek istersen ücretsiz bilgi testleri merkezindeki Python ve Java seviye testlerini deneyebilirsin.

Dijkstra negatif kenarlarda neden güvenilir değildir?

Dijkstra'nın doğruluğu tek bir varsayıma dayanır: bir düğüm kesinleştirildiğinde, geri kalan düğümlerden geçen hiçbir yol ona daha kısa bir rota sunamaz. Ağırlıklar negatif değilse bu doğrudur, çünkü bir yola kenar eklemek toplam uzaklığı asla azaltmaz. Negatif bir kenar bu varsayımı bozar. Daha sonra keşfedilen bir yol, yolun sonunda uzaklığı düşürebilir. Oysa algoritma o düğümü çoktan kesinleştirmiştir ve geri dönüp bakmaz.

Küçük bir yönlü graf üzerinde görelim. Kenarlar şunlar:

  • A → B, ağırlık 2
  • A → C, ağırlık 3
  • C → B, ağırlık -2

Başlangıç düğümü A olsun. İlk turda geçici uzaklıklar B = 2 ve C = 3 olur. En küçük geçici uzaklık B'dedir, dolayısıyla Dijkstra B'yi 2 olarak kesinleştirir. Sonra C'ye geçer ve C → B kenarına bakar, ama B artık kapanmıştır. Oysa A → C → B yolunun uzunluğu 3 + (-2) = 1'dir. Gerçek en kısa uzaklık 1'dir, algoritma ise 2 döndürür.

Örnekteki kenarın yönlü olması önemlidir. Yönsüz bir kenar her iki yönde de geçilebildiği için negatif ağırlıklı yönsüz bir kenar, ileri geri gidip gelerek toplamı sürekli düşüren bir negatif döngü yaratır ve en kısa yol kavramı anlamını yitirir.

Grafında negatif ağırlıklı kenar varsa Dijkstra'yı hiç kullanma. Bu tür durumlar için Bellman-Ford adıyla anılan farklı bir algoritma ailesi vardır.

Dijkstra ne zaman kullanılır, ne zaman kullanılmaz? Karmaşıklık ve karar çerçevesi

Bir problemde Dijkstra'ya uzanmadan önce şu soruları sırayla yanıtla:

  1. Tüm ağırlıklar negatif olmayan mı? Sıfır ve pozitif değerler sorun çıkarmaz. Tek bir negatif kenar varsa Dijkstra güvenilmezdir.
  2. Tek bir başlangıçtan tüm düğümlere en kısa yol mu aranıyor? Dijkstra tam olarak bu problemi çözer. Her düğüm çiftinin birbirine uzaklığı gerekiyorsa algoritmayı her başlangıç için ayrı çalıştırman gerekir.
  3. Ağırlıklar eşit mi, yoksa yalnızca kenar sayısı mı önemli? Bu durumda ağırlıkları hesaba katmayan, düzey düzey ilerleyen daha basit bir gezinme (BFS) aynı sonucu daha sade bir kodla verebilir.
  4. Graf yoğun mu, seyrek mi? Uygulama seçimi buna bağlıdır; aşağıda ayrıntısı var.
  5. Yolun kendisi de gerekli mi? Yalnızca uzaklık yetmiyorsa her güncellemede önceki düğüm kaydını da tut ve yolu sondan başa kur.

Karmaşıklık, uygulamanın en küçük geçici uzaklığı nasıl bulduğuna göre değişir. Düğüm dizisi tutup her turda en küçük değeri doğrusal aramayla bulursan toplam iş yaklaşık O(V²) olur. Komşuluk listesi ve ikili yığın tabanlı bir öncelik kuyruğu (Python'da heapq) kullanırsan O((V+E) log V) mertebesine inersin. Seyrek grafta kenar sayısı düğüm sayısına yakın kalır ve yığın tabanlı sürüm genellikle avantajlıdır. Kenar sayısı V² değerine yaklaşan yoğun grafta ise dizi tabanlı sürüm de rekabetçi kalabilir. Bu yüzden mutlak bir "en hızlı" yoktur; seçimi grafın yapısı belirler.

Öğrenmeyi pekiştirmek için kâğıda 6-7 düğümlü, ağırlıkları negatif olmayan yeni bir graf çiz. Beş düğümlü örnekteki gibi bir tablo hazırla ve her turda kesinleşen düğümü, güncellenen komşuları ve önceki düğüm kaydını kendi başına doldur. Sonra aynı grafı heapq kodunda çalıştırıp çıktıyı tablonla karşılaştır. Aradaki fark çoğu zaman bir gevşetme adımını atlamandan çıkar. Bu çalışmayı bitirdiğinde blogdaki diğer algoritma ve veri yapıları yazılarına göz atarak bir sonraki konuya geçebilirsin.

Sık Sorulan Sorular

Dijkstra algoritması sıfır ağırlıklı kenarlarda çalışır mı?

Evet. Algoritmanın şartı ağırlıkların negatif olmamasıdır; sıfır bu şarta uyar. Sıfır ağırlıklı bir kenar toplam uzaklığı azaltmaz, yalnızca artırmaz, bu yüzden kesinleştirme mantığı bozulmaz.

Dijkstra algoritması yönlü grafikte de kullanılabilir mi?

Evet. Gevşetme adımında yalnızca düğümden çıkan kenarlara bakılır, dolayısıyla kenar yönleri doğal olarak hesaba katılır. Yönlü grafta da ağırlıkların negatif olmaması gerekir.

Dijkstra ile BFS arasındaki fark nedir?

BFS yolu kenar sayısıyla ölçer, Dijkstra ise kenar ağırlıklarının toplamıyla. Tüm kenarlar aynı ağırlıktaysa ikisi aynı sonucu verir ve BFS daha basittir. Ağırlıklar farklıysa BFS'nin bulduğu en az kenarlı yol, en düşük toplam ağırlıklı yol olmayabilir.

Dijkstra algoritması yalnızca iki düğüm arasındaki yolu mu bulur?

Hayır. Standart hâliyle başlangıç düğümünden tüm düğümlere en kısa uzaklıkları hesaplar. Yalnızca belirli bir hedef düğümle ilgileniyorsan, hedef kesinleştirildiği anda algoritmayı durdurabilirsin.

Dijkstra'yı iyi anlamanın en kısa yolu, küçük bir grafı elle çözüp ardından kodla doğrulamaktır; tablodaki her satırın kodda neye karşılık geldiğini gördüğünde algoritma ezber olmaktan çıkar.

Bu içerik aradığın cevabı verdi mi?
Yanıtın, hangi yazıları geliştirmemiz gerektiğini anlamamıza yardımcı olur.
Bu içeriğin üretilmesinde yapay zeka araçlarından destek alınmıştır.

Bu konudan sonra ne okuyabilirsin?

Tüm yazılar

İlgili Eğitimler

Berk Keskin, yazılım geliştirici ve eğitmen
Yazar

Berk Keskin Kimdir?

Yazılıma 12 yaşında başladı; İzmir Ekonomi Üniversitesi'ni bölüm birincisi ve yüksek şeref öğrencisi olarak tamamladı. Bugün yalnızca eğitim vermekle kalmıyor, sektörde aktif olarak yazılım projeleri geliştiriyor ve gerçek dünya deneyimini birebir derslerine taşıyor. Ezberden uzak, mühendislik zihniyetini merkeze alan sürdürülebilir öğrenme sistemleri tasarlayarak sorgulayan, üreten ve problem çözebilen yeni nesil yazılımcılar yetiştiriyor.

Sektörel Deneyim & Projeler

  • Ticarify Entegrasyon Yazılım logosu CEO Ticarify Entegrasyon YazılımPazaryerleri ve e-ticaret sitelerine otomatik e-fatura kesimi, sipariş ve kargo takibi hizmetleri sunan e-Dönüşüm platformunun API mimarisini ve yazılım ekibini yönetmektedir.
  • Benim Düğünüm logosu CEO Benim DüğünümDijital etkinlik ve anı paylaşım platformu.
  • Siberdizayn logosu Yazılım Ekibi Lideri SiberdizaynYüksek anlık oyuncu trafiğine sahip oyun kontrol panelleri ve sunucu altyapıları geliştiren yazılım ekibine liderlik etmektedir.
  • MEDYOGRAFYA 360° Dijital Çözümler logosu Dijital Strateji Lideri MEDYOGRAFYA 360° Dijital ÇözümlerŞirketlerin dijital çözümlerde uzun vadede nasıl ilerlemesi gerektiği ve dijital dönüşüm süreçlerinin yönetilmesine destek olmaktadır.
  • İzmir Ekonomi Üniversitesi logosu Danışma Kurulu Üyesi İzmir Ekonomi ÜniversitesiMezun olduğu üniversitesinde, Bilgisayar Programcılığı bölümünün akademik müfredatını güncel sektör ihtiyaçlarına göre şekillendirmek adına Danışma Kurulu'nda görev almaktadır.
WhatsApp Hemen Ara