16  Derinlemesine Arama (DFS)

DFS = özyinelemeli derine in, geri çekil; erişilebilirlik O(E) (ebeveyn ağacı, en kısa değil); full DFS → bağlı bileşenler O(V+E); DAG’da ters bitiş sırası = topolojik sıra (u→v ⇒ f(u)<f(v), benzersiz değil); geri kenar (v → atası) = çevrim; bağımlılık çözen her sistem (make/npm/pip) içten içe bunu çalıştırır

NotBölüm bilgisi

Bir önceki ders BFS’i (enine arama) verdi; bu ders onun kardeşi DFS’i çözer ve üç güçlü uygulamayı açar: erişilebilirlik, bağlı bileşenler, topolojik sıralama (+ çevrim tespiti).

16.1 Bu Derste Ne Var?

Ders 13 (L9) BFS’i (enine arama) verdi; Ders 14 (Quiz 1 Gözden Geçirme, Jason Ku) araya girdi. Bugün yine Justin Solomon ile BFS’in kardeşi DFS (depth-first search, derinlemesine arama) ile devam ediyoruz. DFS, çizgeyi “olabildiğince derine in, sonra geri çekil” mantığıyla gezer ve üç güçlü uygulamayı açar: erişilebilirlik, bağlı bileşenler, topolojik sıralama (+ çevrim tespiti).

“in breadth-first search, we’re like, drawing concentric circles. In depth-first search… we’re like, shooting outward until we reach the outer boundary.” — Solomon, 6:55

Üç ana fikir bu derste yan yana gelir:

  1. DFS = özyinelemeli gezinme — bir düğümden komşularına in, her komşu kendi komşularına insin; erişilebilirliği \(O(E)\)’de çöz.
  2. Bağlı bileşenler — full DFS (her düğüm üzerinde döngü) ile \(O(V + E)\)’de tüm “kümeleri” bul.
  3. Topolojik sıralama — bir DAG’da, DFS bitiş sırasının tersi geçerli bir bağımlılık sıralaması verir; aynı teknik çevrim tespiti yapar.
flowchart TD
    A["Ders 15 (L10): Derinlemesine Arama (DFS)"] --> D["DFS özyinelemeli iskelet<br/>derine in, geri çekil"]
    D --> D1["ziyaretsiz komşuya in<br/>dibe vur, geri çekil (yığın boşalır)"]
    A --> R["erişilebilirlik O(E)<br/>ebeveyn ağacı P(v)"]
    R --> R1["kaynaktan bir yol — en KISA değil<br/>yalnız erişilebilir kenarlara dokunur"]
    A --> C["bağlı bileşenler<br/>full DFS"]
    C --> C1["tüm düğümler üzerinde döngü<br/>her ada bir DFS ağacı, O(V+E)"]
    A --> T["DAG + topolojik sıra<br/>ters bitiş sırası"]
    T --> T1["u→v ⇒ f(u)&lt;f(v)<br/>benzersiz değil"]
    A --> Y["çevrim tespiti<br/>geri kenar"]
    Y --> Y1["v'den atasına kenar = çevrim<br/>topolojik sıra var ancak ve ancak DAG"]

    classDef root fill:#fef3c7,stroke:#b45309,stroke-width:3px,color:#1f2937
    classDef branch fill:#f3f4f6,stroke:#374151,stroke-width:2px,color:#1f2937
    classDef leaf fill:#ffffff,stroke:#9ca3af,stroke-width:1px,color:#1f2937
    class A root
    class D,R,C,T,Y branch
    class D1,R1,C1,T1,Y1 leaf
Şekil 16.1: Ders 15’in (L10) kavram haritası: kök = derinlemesine arama (DFS). Beş dal — (1) DFS özyinelemeli iskelet: bir düğümden ziyaretsiz komşuya in, dibe vur, geri çekil (özyineleme çözülür). (2) erişilebilirlik O(E): ebeveyn ağacı P(v) ile kaynaktan bir yol — en kısa DEĞİL; DFS yalnız erişilebilir kenarlara dokunur. (3) bağlı bileşenler: full DFS tüm düğümler üzerinde döngü → her ada bir DFS ağacıyla O(V+E)’de bulunur. (4) DAG + topolojik sıra: yönlü çevrimsiz çizgede ters bitiş sırası = topolojik sıralama (u→v ⇒ f(u)<f(v)), benzersiz değil. (5) çevrim tespiti: geri kenar (v’den atasına kenar) bir çevrimi tamamlar; topolojik sıra var ancak ve ancak DAG. Sonuç: tek özyinelemeli iskelet, dört güç.
İpucuBuilder Notu — Tek İskelet, Dört Güç

DFS, “derine in, geri çekil” diyen tek bir özyinelemeli iskelettir — ama o tek iskeletten dört ayrı güç çıkar. Önce nasıl gezdiğini (özyineleme), sonra ne sorabildiğini (erişilebilirlik, bileşenler, sıra, çevrim) sorarız.

  • İleriye → topolojik sıralama her yerde: make, paket yöneticileri (npm/pip bağımlılık çözümü), build sistemleri, görev zamanlayıcılar — hepsi DAG’da topolojik sıralama çalıştırır.
  • İleriye → çevrim tespiti: deadlock tespiti, döngüsel bağımlılık uyarısı (import cycle), elektronik tablo formül döngüsü.
  • Geriye → BFS (Ders 13): ikisi de \(O(V + E)\) çizge gezme iskeleti; BFS en kısa yol (ağırlıksız) verir, DFS yapısal sorular (DAG mı? bileşenler? sıra?) için.
  • İleriye → Dijkstra (Ders 16-19 (L11-L13)): DFS/BFS ağırlıksız; ağırlık girince öncelik kuyruğu gelir.

Tek cümle: DFS, çizgeyi özyinelemeli olarak derinlemesine gezer; bu tek iskeletten erişilebilirlik (\(O(E)\)), bağlı bileşenler (\(O(V + E)\)) ve topolojik sıralama/çevrim tespiti çıkar.

16.2 1. BFS’ten DFS’e: İki Arama Stratejisi

İki temel çizge gezme tekniği vardır. BFS kaynaktan dışa eşmerkezli daireler çizer: önce \(L_1\) (uzaklık 1), tüm \(L_1\) bitmeden \(L_2\)’ye geçilmez. DFS ise tam tersi: ilk düğümden başlar, gidebildiği kadar derine koşar, tıkanınca geri çekilir (backtrack).

“shooting outward until we reach the outer boundary, and then exploring the graph that way.” — Solomon, 6:55

İkisi de aynı çizge terminolojisi üzerine kurulu: \(G = (V, E)\), \(\text{Adj}^{+}(u)\) çıkış komşuları, yol (path), basit yol (simple path — aynı düğüm iki kez yok). “Doğrusal zaman” çizgede \(O(V + E)\) demektir (girdiyi saklamak için gereken yer).

Şekil 16.2 aynı 7 düğümlü çizge üzerinde iki stratejiyi yan yana koyar: solda BFS dalga dalga (seviye tonları + eşmerkezli halkalar), sağda DFS tek bir kıvrımlı izle dibe dalar (ziyaret sırası \(a \to b \to d \to c \to e \to f \to g\)) ve tıkanınca geri çekilir.

Şekil 16.2: İki arama stratejisi — AYNI çizge: BFS dalga dalga · DFS dibe dalar (L10 §1, İMZA figür). SOL panel BFS = kaynaktan eşmerkezli halkalar, katman katman (önce TÜM L1={b,c}, sonra TÜM L2={d,e}…); her düğüm seviye tonuyla (L0 a amber kaynak → L4 g beyaz+slate). SAĞ panel DFS = aynı çizge, tek AMBER kıvrımlı ok zinciri dibe dalar (ziyaret sırası a→b→d→c→e→f→g; her ok üstünde sıra numarası); sona varınca geri-çekilme (kesikli gri geri-oklar, özyineleme yığını boşalır). Kontrast: BFS b ve c’yi BİRLİKTE (aynı katman) görür; DFS b’den HEMEN d’ye dalar, c’ye ancak geri çekilince 4. sırada varır. BFS = ağırlıksız en kısa yol; DFS = yapısal sorular (DAG mı? bileşenler? topolojik sıra? çevrim?). Veri MOTORDAN: bfs_levels(build_example_graph(),‘a’)=[[a],[b,c],[d,e],[f],[g]]; dfs_visit_order(…,‘a’)[‘order’]=[a,b,d,c,e,f,g] (Solomon 6:55).

16.3 2. Erişilebilirlik Problemi ve Ebeveyn Ağacı

Erişilebilirlik (reachability): bir kaynak \(s\)’den yönlü kenarları izleyerek hangi düğümlere ulaşılır?

“the reachability problem is just asking, which nodes can I reach from a given source?” — Solomon, 8:20

BFS ile çözülebilir (erişilemeyen düğümün mesafesi \(\infty\)), ama daha doğrudan bir yol var. “Kanıt” istersek (sadece “ulaşılır” değil, “nasıl”), her düğümü öncülü (predecessor) \(P(v)\) ile etiketleriz — kaynaktan o düğüme giden bir yolda önceki düğüm. Yolu, \(P\)’yi geriye izleyip listeyi ters çevirerek kurarız.

Önemli fark (Ders 13’ün en kısa yol ağacından): buradaki ebeveyn ağacı en kısa yolu garanti etmez — erişilebilirlikte yolun kısalığı umurumuzda değil, sadece varlığı. Yine de bir ağaçtır (çevrim olamaz).

16.4 3. DFS Algoritması

DFS özyinelemeli bir visit fonksiyonudur: kaynağı işaretle; her komşu \(v\) için, henüz ziyaret edilmemişse (\(P(v) = \text{None}\)) ebeveynini “ben” yap ve özyinelemeli olarak ona in.

Çalışılan Örnek — gezinme sırası. Kaynak 1’den başla. 1’in tek komşusu 2 → visit(2). 2’nin komşuları 3 ve 5; önce 3 → visit(3) → visit(4). Özyineleme dibe vurdu, geri çekil. 2 sonraki komşusu 5’e iner → visit(5). Sıra: \(1 \to 2 \to 3 \to 4 \to (\text{geri}) \to 5\). Dikkat: bu seviye kümelerini izlemez — DFS dibe (4) gidip sonra 2’ye geri sarıp 5’i çağırdı. “Geri çekilme” = özyinelemenin çözülmesi.

def dfs(adj, s, parent=None):
    if parent is None:
        parent = {s: None}        # kaynagi ziyaret et
    for v in adj[s]:
        if v not in parent:       # henuz ziyaret edilmemis
            parent[v] = s         # ebeveyni = ben
            dfs(adj, v, parent)   # ozyinele
    return parent

Şekil 16.3 bu çalışılan örneği adım adım izler: üstte yönlü çizge (\(1 \to 2 \to 3 \to 4\) dibe in, sonra geri çekilip 5’e dal), altta olay şeridi — in/out olaylarının sırası, \(\text{out}(4), \text{out}(3)\) olaylarının \(\text{in}(5)\)’ten önce gelmesi (dibe vur, geri sar, sonra 5).

Şekil 16.3: DFS çalışılan örnek: 1→2→3→4 dibe in, sonra geri çekilip 5’e dal (L10 §3, İMZA figür). ÜST: yönlü çizge — kenarlar 1→2, 2→3, 2→5, 3→4. Ziyaret (ileri) okları AMBER + sıra numarası: 1→2 [1], 2→3 [2], 3→4 [3], sonra 2→5 [4]. Geri-çekilme okları KESİKLİ GRİ: 4→3, 3→2 (özyineleme çözülmesi; 5 ziyaretinden ÖNCE). ALT: olay şeridi — in(1) in(2) in(3) in(4) out(4) out(3) in(5) out(5) out(2) out(1); ‘in’ amber dolu, ‘out’ soluk çerçeve. out(4) ve out(3), in(5)’ten ÖNCE: dibe vur (4), geri sar (out 4,3), sonra 5. Seviye kümeleri İZLENMEZ — geri çekilme = özyinelemenin çözülmesi (out’lar in’lerin TERSİ sırada kapanır). Veri MOTORDAN: dfs_visit_order(build_dfs_example(),1)[‘order’]=[1,2,3,4,5]; events=[in1,in2,in3,in4,out4,out3,in5,out5,out2,out1] (Solomon L10 §3).

16.5 4. DFS Doğruluğu

İddia: DFS, erişilebilir her \(v\)’yi ziyaret eder ve ebeveynini doğru atar.

Çalışılan Örnek — kaynağa uzaklık üzerinden tümevarım. Kaynağa uzaklık \(k\) üzerinden tümevarım.

  • Temel (\(k = 0\)): uzaklık 0 olan tek düğüm kaynağın kendisidir; algoritma ilk satırda onu doğru kurar. ✓
  • Adım (\(k \to k+1\)): \(v\), kaynaktan uzaklık \(k+1\) olsun. En kısa yolda \(v\)’den bir önceki düğüm \(u\)’nun uzaklığı \(k\)’dır → tümevarım varsayımıyla \(u\) doğru ziyaret edilir. visit(\(u\)) çağrıldığında, \(v \in \text{Adj}^{+}(u)\) olduğundan DFS \(v\)’yi değerlendirir. İki durum: ya \(P(v) \neq \text{None}\) (zaten uygun bir ebeveyn bulunmuş) ya da \(P(v) = \text{None}\) (bir sonraki satır ebeveyni doğru atar). Her iki durumda da \(v\)’nin ebeveyni doğru. ✓

Sezgisel olarak basit; biçimsel tümevarım totoloji gibi hissettirebilir ama değil.

16.6 5. DFS Çalışma Süresi O(E)

Her düğüm en fazla bir kez ziyaret edilir (visit her düğüm için bir kez çağrılır); her kenar en fazla bir kez gezilir (kenarın “çıkış” düğümü bir kez ziyaret edildiğinden). Önemli ayrım: BFS, başta \(O(V)\) yer ayırdığı için \(O(V + E)\)’dir; DFS ise yalnızca erişilebilir kenarlara dokunur, hiç erişilemeyen düğümü görmez → \(O(E)\).

“depth-first search… it just takes order e time.” — Solomon, 22:09

(Kenarsız bir çizgede BFS yine \(O(V)\), DFS ise \(O(E) = O(0)\) işi yapar; sınırlar birebir aynı değildir.)

16.7 6. DFS En Kısa Yol Vermez

DFS’in ürettiği yol en kısa olmak zorunda değildir.

“there’s no reason why the path that we get should be the shortest.” — Solomon, 24:01

Uç örnek: bir çevrim çizgesi (büyük halka). Kaynaktan başlayıp komşu komşuyu özyinelemeli çağırırsak, son düğüme 4 düğümlük bir zincirin arkasından varırız — oysa tek bir kenarla doğrudan gidilebilirdi. DFS o kenarı seçmedi. Bu yüzden ağırlıksız en kısa yol için BFS kullanılır; DFS yapısal sorular içindir.

16.8 7. Bağlılık ve Bağlı Bileşenler

Bir çizge bağlı (connected) ise her düğümden her düğüme bir yol vardır.

“a graph is connected if there’s a path getting from every vertex to every other vertex.” — Solomon, 25:14

Yönlü çizgede bağlılık tuhaftır (\(u \to v\) var ama \(v \to u\) yok olabilir), bu yüzden çoğunlukla yönsüz çizgelerde konuşulur: düğümler “kümeler” hâlinde gelir — bir bağlı bileşen (connected component).

Bağlı bileşenler problemi: tüm kümeleri listele. Çözüm full DFS: tüm düğümler üzerinde bir döngü; düğüm henüz ziyaret edilmemişse ondan DFS başlat (o bileşeni “flood fill” eder), topla, devam et. Her kenar en fazla bir kez gezilir (bir düğüm iki bileşende olamaz) → \(O(V + E)\).

def full_dfs(adj, V):
    parent = {}
    components = []
    for s in V:                   # tum dugumler uzerinde dongu
        if s not in parent:       # yeni bilesen
            parent[s] = None
            dfs(adj, s, parent)
            components.append(s)   # bu bilesenin temsilcisi
    return components, parent

Şekil 16.4 full DFS’i “ada keşfi” olarak gösterir: üç bağlı bileşen (\(\{1,2,3\}\), \(\{4,5\}\), \(\{6\}\)), her birinin temsilci kökü (\(1, 4, 6\)), ve altta dış-döngünün düğümleri sırayla tarayışı (ziyaretsiz köke yeni DFS başlat, görülmüşü atla).

Şekil 16.4: Full DFS = bağlı bileşenler: ziyaretsiz her köke yeni DFS başlat (ada ada) (L10 §7, İMZA figür). ÜST: 3 ada çizgesi — küme 1 {1,2,3} (üçgen-vari, amber halo, bileşen C₁), küme 2 {4,5} (çift, slate halo, C₂), küme 3 {6} (tek düğüm, beyaz halo, C₃); her ada altında bileşen etiketi. Temsilci kökler (her bileşenin ilk ziyaret edilen düğümü) amber dolgulu + ‘kök’ etiketi: 1, 4, 6. ALT: full DFS dış-döngü şeridi — düğümler 1..6 SIRAYLA taranır; 1 ziyaretsiz → DFS başlat (ada 1’i sular), 2,3 görülmüş → atla, 4 ziyaretsiz → DFS başlat (ada 2), 5 atla, 6 ziyaretsiz → DFS başlat (ada 3); amber ‘DFS’ rozeti her başlatmada. Dış döngü her düğüme 1 kez bakar + her kenar en fazla 1 kez gezilir → O(V+E). Veri MOTORDAN: connected_components=[[1,2,3],[4,5],[6]]; full_dfs temsilcileri=[1,4,6] (Solomon L10 §7).

16.9 8. Yönlü Çevrimsiz Çizge (DAG) ve Topolojik Sıralama

Bir DAG (Directed Acyclic Graph): yönlü kenarlı, çevrimsiz çizge. (Yönlendirilmiş bir ağaç bir DAG örneğidir.)

“a DAG is a Directed Acyclic Graph.” — Solomon, 32:28

Topolojik sıralama: her düğüme bir sıra indeksi \(f\) atayan, şu özelliği sağlayan bir düzen: her \(u \to v\) kenarı için \(f(u) < f(v)\) (\(u\), \(v\)’den önce gelir).

“if I have a directed edge from u to v, then f of u is less than f of v.” — Solomon, 34:46

Topolojik sıralama benzersiz değildir\(A \to B\), \(A \to C\), \(B \to D\), \(C \to D\) çizgesinde hem “A C B D” hem “A B C D” geçerlidir. Bu “özgürlük”, algoritmanın çoktan birini bulmasına izin verir.

16.10 9. Bitiş Sırası → Topolojik Sıralama

Bitiş sırası (finishing order): full DFS çalıştır; bir düğümün visit çağrısı tamamlandığında (tüm komşuları gezildiğinde) onu sıraya ekle. İddia: bir DAG’da, bitiş sırasının tersi geçerli bir topolojik sıralamadır.

“the reverse of the finishing order is a topological order.” — Solomon, 37:54

Çalışılan Örnek — kanıt (iki durum). Bir \(u \to v\) kenarı al; ters bitiş sırasında \(u\)’nun \(v\)’den önce geldiğini göstermeliyiz.

  • Durum 1 — \(u\), \(v\)’den önce ziyaret edildi: visit(\(u\)), \(v\)’yi (henüz ziyaretsizse) çağırır; visit(\(v\)), visit(\(u\))’dan önce tamamlanır. Ters sırada bu, \(u\)’yu \(v\)’nin önüne koyar. ✓
  • Durum 2 — \(v\), \(u\)’dan önce ziyaret edildi: çizge çevrimsiz olduğundan \(v\)’den \(u\)’ya yol yoktur (olsaydı çevrim olurdu). O hâlde visit(\(v\)), \(u\)’yu hiç görmeden tamamlanır → Durum 1’le aynı sonuç: ters sırada \(u\), \(v\)’den önce. ✓

Şekil 16.5 bu mekanizmayı gösterir: örnek DAG, full DFS’in bitiş sırası \([D, B, C, A]\) (D yaprak, ilk biter; A kök, son biter), ve onun tersi = topolojik sıra \([A, C, B, D]\); her DAG kenarı için \(f(u) < f(v)\) onayı yeşil rozetle, ve “benzersiz değil” notu (\([A, B, C, D]\) de geçerli).

Şekil 16.5: DAG’da topolojik sıra = TERS bitiş sırası (tek DFS geçişi, O(V+E)) (L10 §8-9, İMZA figür). ÜST-SOL: örnek DAG — A üstte, B ve C ortada yan yana, D altta (elmas); yönlü oklar A→B, A→C, B→D, C→D. ORTA serit: BİTİŞ SIRASI (visit tamamlanınca out() ile eklenir) [D, B, C, A]; D ilk biter (yaprak), A son biter (kök). ‘TERSE ÇEVİR’ dönüş oku. ALT serit: TOPOLOJİK SIRA = ters bitiş = [A, C, B, D] (amber kutular); her DAG kenarı için f(u)<f(v) onayı yeşil ✓ rozeti (A<C, A<B, B<D, C<D); verify_topological=True. YAN NOT: topolojik sıra BENZERSİZ DEĞİL — [A, C, B, D] ve [A, B, C, D] ikisi de geçerli (B-C arası kenar yok); ters bitiş bunlardan BİRİNİ bulur. Kanıt iki durum (Solomon 37:54). Veri MOTORDAN: build_dag_example={A:[B,C],B:[D],C:[D],D:[]}; finishing_order=[D,B,C,A]; topological_order=[A,C,B,D]; verify=True.

16.11 10. Çevrim Tespiti

DAG değilsek topolojik sıralama elde edemeyiz. Yani: ters bitiş sırasını hesapla, sonra her kenarın \(f(u) < f(v)\) ilişkisine uyup uymadığını kontrol et. Uymayan bir kenar bulursak çizge DAG değildir → bir çevrim vardır. (Aslında: topolojik sıralama var \(\iff\) çizge DAG.)

Çevrimi yalnızca tespit değil bulmak için: \(G\) çevrim içeriyorsa, full DFS bir \(v\) düğümünden onun bir atasına (ancestor) giden bir kenar gezer (atası = özyineleme ağacında \(v\)’den önce gelen düğüm).

“full DFS will traverse an edge from a vertex v to some ancestor of v.” — Solomon, 48:20

Kanıt taslağı: çevrim \(v_0 \to v_1 \to \ldots \to v_k \to v_0\) olsun; \(v_0\)’ı DFS’in ilk gördüğü düğüm seç. \(v_0\)’ın özyineleme ağacı tamamlanmadan, ondan erişilebilen \(v_1, \ldots, v_k\) de tamamlanır; \(v_k\) komşularını gezerken \(v_0\) kenarını görür — bu, \(v_k\)’den atası \(v_0\)’a giden geri kenardır (back edge). DFS sırasında bu geri kenarı yakaladığın an çevrimi bulmuş olursun.

Şekil 16.6 bu ayrımı iki panelle gösterir: solda çevrimli çizge (\(1 \to 2 \to 3 \to 1\) + \(4 \to 1\)), DFS yığını \(1 \to 2 \to 3\) aktifken \(3 \to 1\) bir geri kenardır (1, 3’ün atası) → çevrim \([1,2,3,1]\), DAG değil; sağda \(3 \to 1\) kaldırılmış, geri kenar yok → DAG, topolojik sıra \([4,1,2,3]\).

Şekil 16.6: Çevrim tespiti: geri kenar (aktif yığındaki ataya kenar) = çevrim (L10 §10, İMZA figür). SOL panel — çevrimli çizge: 1→2→3→1 üçgeni + 4→1 dış kenarı. DFS özyineleme yolu 1→2→3 amber (aktif yığın). 3’ten 1’e giden kenar KALIN AMBER KESİKLİ + ‘geri kenar (back edge)’ etiketi — 1, 3’ün ATASIDIR (özyineleme yığınında hâlâ aktif). Sonuç: ÇEVRİM VAR → DAG DEĞİL; çevrim [1,2,3,1], topolojik sıra YOK. SAĞ panel — aynı yapı ama 3→1 kenarı KALDIRILMIŞ (3 çıkışsız): DFS temiz biter, geri kenar yok, çevrim yok → DAG; ters bitiş sırası = topolojik sıra [4,1,2,3]. Full DFS çevrim varsa bir v düğümünden atasına giden kenarı gezer. Veri MOTORDAN: find_cycle({1:[2],2:[3],3:[1],4:[1]})=[1,2,3,1]; find_cycle(3→1 kaldırılmış)=None; topological_order=[4,1,2,3]; verify=True (Solomon 48:20).

16.12 Bu Dersin Özeti

  1. DFS = özyinelemeli “derine in, geri çekil”; BFS eşmerkezli dairelerken DFS dışa fırlar.
  2. Erişilebilirlik: ebeveyn ağacı \(P(v)\) ile bir yol (en kısa değil) ver; ağaç (çevrimsiz).
  3. DFS doğruluğu: uzaklık \(k\) üzerinden tümevarım; \(u\) (\(k\)) doğruysa \(v\) (\(k+1\)) de doğru.
  4. Çalışma süresi: DFS \(O(E)\) (yalnız erişilebilir kenarlar); BFS \(O(V + E)\) (başta \(O(V)\) yer).
  5. Bağlı bileşenler: full DFS, tüm düğümler üzerinde döngü → \(O(V + E)\).
  6. DAG + topolojik sıralama: \(f(u) < f(v)\); benzersiz değil; ters bitiş sırası = topolojik sıra.
  7. Çevrim tespiti: topolojik sıra \(\iff\) DAG; geri kenar (\(v \to\) atası) çevrimi verir.

Şekil 16.7 dersi tek bir sentez figüründe toplar: ortada DFS (\(O(V+E)\) özyinelemeli iskelet), dört köşede dört güç — erişilebilirlik, bağlı bileşenler, topolojik sıra, çevrim tespiti — her biri motordan gelen bir mini sonuçla.

Şekil 16.7: DFS = tek özyinelemeli iskelet → dört güç (L10 sentezi, İMZA figür). ORTADA büyük amber kutu: DFS — derine in, geri çekil (özyinelemeli visit, O(V+E)). Dört köşede uydu kutusu, merkezden oklarla bağlı, her biri motordan mini sonuç: (1) ERİŞİLEBİLİRLİK O(E) — ebeveyn ağacı (kaynak 1) {1:·, 2:1, 3:2, 4:3, 5:2}, yol 1→2→3→4 en KISA DEĞİL (DFS yolu ≠ en kısa yol). (2) BAĞLI BİLEŞENLER O(V+E) — full DFS sel-doldurma → {a,b,c} {d,e} {f,g,h}, 3 ada. (3) TOPOLOJİK SIRA — ters bitiş sırası (DAG) A→C→B→D, her u→v’de f(u)<f(v) ✓ (build sistemleri make·npm·pip). (4) ÇEVRİM TESPİTİ — geri kenar (aktif yığına) 1→2→3→1, atasına dönen kenar → çevrim (deadlock·import döngüsü). Bağımlılık çözen her sistem içten içe bunu çalıştırır. Veri MOTORDAN: dfs(build_dfs_example(),1)={1:None,2:1,3:2,4:3,5:2}; connected_components=[[a,b,c],[d,e],[f,g,h]]; topological_order(build_dag_example())=[A,C,B,D]; find_cycle({1:[2],2:[3],3:[1]})=[1,2,3,1].
ÖnemliTek Bir Cümle

DFS, çizgeyi özyinelemeli olarak derinlemesine gezen tek bir iskelettir; ondan erişilebilirlik (\(O(E)\)), bağlı bileşenler ve topolojik sıralama/çevrim tespiti — hepsi \(O(V + E)\) içinde — doğal olarak türer.

16.13 Kontrol Soruları

Cevap: BFS, kaynaktan dışa katman katman (seviye kümeleri) ilerler — bir seviye bitmeden sonrakine geçmez. DFS, bir dalda olabildiğince derine iner, tıkanınca geri çekilir. Süre farkı uygulamadan gelir: bu dersteki BFS başta \(O(V)\) yer ayırdığı için (erişilemeyenler dahil) \(O(V + E)\)’dir; DFS yalnızca kaynaktan erişilebilen kenarlara dokunur, hiç erişilemeyen düğümü görmez, dolayısıyla \(O(E)\). (full DFS ise tüm düğümler üzerinde döngü kurduğundan yine \(O(V + E)\).)

Cevap: DFS, bir komşuya “ilk denk geldiği” sırada iner — bu sıra en kısa yolu izlemez. Çevrim çizgesi (halka) uç örnektir: kaynaktan komşu komşuyu özyinelemeli çağırınca son düğüme uzun bir zincirin arkasından varılır, oysa tek kenarla doğrudan gidilebilirdi. DFS o kısa kenarı seçmez. Bu yüzden ağırlıksız en kısa yol için BFS kullanılır; DFS yapısal sorular (DAG mı, bileşenler, sıra) içindir.

Cevap: \(u \to v\) kenarı var. \(v\) önce ziyaret edildiyse, visit(\(v\)) tamamlanmadan \(u\)’yu görür mü? Görmesi için \(v\)’den \(u\)’ya bir yol gerekir — ama \(u \to v\) zaten var, \(v \to \ldots \to u\) olsaydı bir çevrim oluşurdu. Çizge DAG (çevrimsiz) olduğundan bu imkânsız. O hâlde visit(\(v\)), \(u\)’yu hiç görmeden tamamlanır; ters bitiş sırasında \(u\), \(v\)’den önce gelir (Durum 1 ile aynı sonuç). Çevrimsizlik olmasaydı iddia çökerdi.

Cevap: full DFS ile ters bitiş sırasını hesapla; her kenar \(f(u) < f(v)\) ilişkisine uyuyorsa çizge bir DAG’dır (topolojik sıralama var \(\iff\) DAG). Bir kenar bu ilişkiyi bozuyorsa çizge DAG değildir → çevrim vardır. Çevrimi bulmak için DFS sırasında bir düğümden atasına giden bir kenar (geri kenar, back edge) ara; o geri kenar bulunduğu an, atadan o düğüme inen özyineleme zinciri + geri kenar bir çevrim oluşturur.

16.14 Egzersizler

Egzersiz 1. Verilen yönlü bir çizgede, belirli bir kaynaktan DFS gezinme sırasını ve ebeveyn ağacı \(P\)’yi elle çıkar; aynı çizgede BFS sırasıyla karşılaştır.

Egzersiz 2. Python’da özyinelemeli DFS’i (yukarıdaki dfs) yığın (stack) tabanlı özyinelemesiz bir sürüme dönüştür; çıktının ebeveyn ağacının aynı kaldığını doğrula.

Egzersiz 3. full DFS ile bir yönsüz çizgenin bağlı bileşen sayısını hesaplayan bir fonksiyon yaz; süresinin \(O(V + E)\) olduğunu argümanla göster.

Egzersiz 4. Küçük bir DAG için tüm geçerli topolojik sıralamaları elle listele; ters bitiş sırasının bunlardan biri olduğunu doğrula.

Egzersiz 5. DFS’i, bir geri kenar (atası ziyarette olan bir komşu) bulduğunda çevrimi düğüm listesi olarak döndürecek şekilde genişlet.

16.15 Sonraki Ders İçin Hazırlık

UyarıSonraki: Ders 16 (L11) — Ağırlıklı En Kısa Yollar

Ders 16 (L11): Ağırlıklı En Kısa Yollar — Jason Ku ile, kenarlara ağırlık ekliyoruz: artık “en az kenar” değil, “en az toplam ağırlık” arıyoruz. BFS/DFS yetmez; ağırlıklar (hatta negatif ağırlıklar) yeni problemler doğurur. Bu, Bellman-Ford ve Dijkstra’ya giden kapının açılışıdır.

Ders 16 Öncesi Yapılacak:

  • Bu dersin egzersizlerini, özellikle Egzersiz 3 (bağlı bileşenler) ve 4 (topolojik sıralama) çöz.
  • DFS doğruluk kanıtını (uzaklık \(k\) tümevarımı) ezberden anlat.
  • Ana cümleyi tekrar oku: “DFS tek iskelet; erişilebilirlik, bileşenler, topolojik sıra ondan türer.”

16.16 Anahtar Kavramlar (Cheat Sheet)

Kavram Tanım Sayfada
DFS Özyinelemeli “derine in, geri çekil”; ebeveyn ağacı \(P(v)\) Böl. 1, 3
Erişilebilirlik \(s\)’den ulaşılan düğümler; \(P\) ile bir yol (en kısa değil) Böl. 2
DFS süresi \(O(E)\) (yalnız erişilebilir kenarlar); full DFS \(O(V + E)\) Böl. 5, 7
Bağlı bileşen Yönsüz çizgede birbirinden erişilebilir küme; full DFS Böl. 7
DAG Yönlü + çevrimsiz çizge Böl. 8
Topolojik sıra \(u \to v \Rightarrow f(u) < f(v)\); benzersiz değil Böl. 8
Bitiş sırası visit tamamlanınca ekle; tersi = topolojik sıra Böl. 9
Çevrim tespiti geri kenar (\(v \to\) atası); topolojik sıra \(\iff\) DAG Böl. 10

16.17 Builder ve OMSCS Bağlantıları

İpucu6 köprü

Bu ders, “tek özyinelemeli iskelet (DFS), dört güç” sezgisini kurar — köprülerin özeti:

  1. Topolojik sıralama → build sistemleri (make, Bazel), paket bağımlılığı (npm/pip), görev zamanlama: DAG’da çalıştırma sırası.
  2. Çevrim tespiti → deadlock, import döngüsü, elektronik tablo formül döngüsü, derleyici bağımlılık grafı.
  3. Bağlı bileşenler → kümeleme, sosyal ağ grupları, görüntü “flood fill”, birlik-bul (union-find) alternatifi.
  4. DFS özyineleme → ağaç/çizge gezme, geri izleme (backtracking) algoritmaları, ifade ağacı değerlendirme.
  5. Erişilebilirlik → ulaşılabilir kod analizi (derleyici), çöp toplama (mark-and-sweep), bağımlılık kapanışı.
  6. \(O(V + E)\) doğrusal → seyreklik bilinci: gerçek çizgeler seyrek; bir gezinmede her kenara bir kez dokun.

ÖnemliTek bir şey alıp gideceksen

DFS, “derine in, geri çekil” diyen tek bir özyinelemeli iskelettir — ama o tek iskeletten erişilebilirlik (\(O(E)\)), bağlı bileşenler (\(O(V + E)\)), topolojik sıralama ve çevrim tespiti çıkar. Bağımlılık çözen her sistem (make, paket yöneticisi, derleyici) içten içe bunu çalıştırır.