Ders 25 / 26
Derine Arama
Yığıtla derinlemesine gezinme, özyinelemeli ve açık yığıtlı biçimler, keşif–bitiş zamanları ve döngü tespiti.
İçindekiler
Enine arama, uzaklığa göre ilerliyordu: yakın olan her şey gezilmeden uzağa gidilmiyordu. Derine arama (depth-first search) karşıt stratejiyi izler — bir yolu tıkanana kadar izler, sonra en son ayrım noktasına döner ve başka bir dal dener.
Yapısal fark tek bir yerdedir: kuyruk yerine yığıt kullanılır. Ağaçlarda seviye sıralı ve derinlik gezinmeleri arasındaki fark neyse, burada da odur.
Özyinelemeli Biçim
Yığıt açıkça tutulmayabilir; özyineleme, çağrı yığıtını aynı iş için kullanır.
def derine_ara(komsuluk: dict[str, list[str]], baslangic: str) -> list[str]: """Derinlemesine gezer; ziyaret sırasını döndürür.""" ziyaret: set[str] = set() sira: list[str] = [] def gez(dugum: str) -> None: ziyaret.add(dugum) sira.append(dugum) for komsu in komsuluk.get(dugum, []): if komsu not in ziyaret: gez(komsu) # tıkanana kadar derine in gez(baslangic) return sira komsuluk = { "bati": ["kuzey", "guney"], "kuzey": ["bati", "merkez"], "guney": ["bati", "merkez"], "merkez": ["kuzey", "guney", "dogu"], "dogu": ["merkez"], } print(derine_ara(komsuluk, "bati")) # ['bati', 'kuzey', 'merkez', 'guney', 'dogu']
Enine arama aynı çizgede ['bati', 'kuzey', 'guney', 'merkez', 'dogu'] sırasını
veriyordu. Derine aramada kuzey düğümünden hemen merkez’e inilir; guney ancak
o dal tükendiğinde ziyaret edilir.
Açık Yığıtlı Biçim
Programlama Temelleri kursunda kurulan dönüşüm burada da geçerlidir: çağrı yığıtı yerine açık bir yığıt tutulabilir. Derin çizgelerde bu, özyineleme sınırına çarpmayı önler.
def derine_ara_yigitla(komsuluk: dict[str, list[str]], baslangic: str) -> list[str]: ziyaret: set[str] = set() sira: list[str] = [] yigit = [baslangic] while yigit: dugum = yigit.pop() # son giren ilk çıkar if dugum in ziyaret: continue ziyaret.add(dugum) sira.append(dugum) for komsu in reversed(komsuluk.get(dugum, [])): if komsu not in ziyaret: yigit.append(komsu) # ters sırada it: sıra korunsun return sira print(derine_ara_yigitla(komsuluk, "bati")) # ['bati', 'kuzey', 'merkez', 'guney', 'dogu']
Komşuların ters sırada itilmesi, ağaç gezinmelerinde sağ çocuğun önce itilmesiyle aynı gerekçeye dayanır: yığıt, itilenlerin tersini verir.
İki biçim arasında ince bir fark vardır: açık yığıtlı sürümde bir düğüm, ziyaret edilmeden önce birden çok kez yığıta girebilir. Bu nedenle çıkarma sırasında yeniden denetlenir. Bellek kullanımı bir miktar artar, davranış aynı kalır.
Keşif ve Bitiş Zamanları
Derine aramanın taşıdığı ek bilgi, her düğüm için iki zaman damgasıdır:
- Keşif zamanı: Düğüme ilk ulaşıldığı an.
- Bitiş zamanı: Düğümün tüm soyu gezildikten sonra geri dönüldüğü an.
Bu iki değer, düğümler arasındaki ilişkiyi sınıflandırmayı sağlar. Bir düğümün keşif–bitiş aralığı, diğerinin aralığını tümüyle kapsıyorsa ikincisi birincinin soyudur; aralıklar kesişmiyorsa iki düğüm ayrı dallardadır. Aralıklar kısmen örtüşemez — bu, gezinmenin yığıt yapısının doğrudan sonucudur.
Bitiş zamanları, sonraki dersteki topolojik sıralamanın temelini oluşturur.
Döngü Tespiti
Derine aramanın en yaygın kullanımlarından biri, yönlü çizgede döngü aramaktır. Ayrım, “ziyaret edildi” ile “hâlâ yığıtta” arasındadır: gezinme sırasında hâlâ açık olan bir düğüme geri dönülüyorsa döngü vardır.
def dongu_var_mi(komsuluk: dict[str, list[str]]) -> bool: """Yönlü çizgede döngü olup olmadığını sınar.""" ziyaret: set[str] = set() acik: set[str] = set() # o an yığıtta olanlar def gez(dugum: str) -> bool: ziyaret.add(dugum) acik.add(dugum) for komsu in komsuluk.get(dugum, []): if komsu in acik: return True # geri kenar: döngü if komsu not in ziyaret and gez(komsu): return True acik.discard(dugum) # dal tamamlandı return False return any(gez(d) for d in komsuluk if d not in ziyaret) cevrimsiz = {"a": ["b", "c"], "b": ["d"], "c": ["d"], "d": []} cevrimli = {"a": ["b"], "b": ["c"], "c": ["a"]} print(dongu_var_mi(cevrimsiz)) # False print(dongu_var_mi(cevrimli)) # True
acik kümesi olmadan, yalnızca ziyaret ile sınama yapılırsa yanlış sonuç alınır:
cevrimsiz çizgesinde d düğümüne iki farklı yoldan ulaşılır, ama bu bir döngü değildir.
İki kavramın ayrılması bu nedenle zorunludur.
İki Gezinmenin Karşılaştırması
| Ölçüt | Enine arama | Derine arama |
|---|---|---|
| Yardımcı yapı | Kuyruk | Yığıt (veya özyineleme) |
| İlerleme | Katman katman | Dal boyunca derine |
| Ağırlıksız en kısa yol | Bulur | Bulmaz |
| Bellek | En geniş katman | En derin yol |
| Doğal kullanım | Uzaklık, yayılma, en az adım | Döngü, sıralama, geri izleme |
| Maliyet |
Dördüncü satır pratik seçimde belirleyici olabilir: geniş ve sığ bir çizgede enine aramanın kuyruğu çok büyür; derin ve dar bir çizgede derine aramanın yığıtı.
Üçüncü satır ise en sık yapılan hatanın kaynağıdır: derine arama bir yol bulur, ama bulduğu yolun en kısa olduğuna dair hiçbir güvence yoktur.
Yinelemeli Derinleştirme
Karşılaştırma tablosu bir ikilem gösterir: enine arama en kısa yolu bulur ama belleği çok kullanabilir; derine arama az bellek kullanır ama en kısa yolu bulmaz.
Yinelemeli derinleştirme, ikisini birleştirir. Derine arama, önce derinlik sınırı bir olarak çalıştırılır; çözüm bulunamazsa sınır ikiye çıkarılır ve arama baştan yapılır. Sınır arttıkça derinleşilir.
İlk bakışta savurgan görünür — aynı üst katmanlar tekrar tekrar gezilir. Ancak dallanma çarpanı birden büyük olduğunda düğümlerin çoğu son katmandadır; tekrar edilen iş, toplamın küçük bir bölümü kalır. Maliyet, enine aramanınkiyle aynı mertebede olur.
Kazanç bellektedir: her an yalnızca tek bir yol yığıtta tutulur. Bulunan ilk çözüm de en sığ olanıdır, çünkü daha küçük sınırlarda çözüm bulunamamıştır.
Yöntem, arama uzayının önceden bilinmediği ve belleğe sığmadığı problemlerde — oyun ağacı araması, bulmaca çözme — tercih edilir.
Kullanım Alanları
- Döngü tespiti. Yukarıdaki gibi; bağımlılık çizgelerinin geçerliliği bu sınamayla denetlenir.
- Bağlı bileşenler. Enine aramada olduğu gibi, her ziyaret edilmemiş düğümden bir gezinme başlatılır.
- Topolojik sıralama. Bitiş zamanlarının tersi, geçerli bir sıralama verir; sonraki dersin konusu.
- Geri izleme. Labirent çözme, bulmaca doldurma ve kısıt sağlama problemleri, derine aramanın seçim ağacı üzerindeki uygulamasıdır.
- Yol bulma. İki düğüm arasında herhangi bir yol aranıyorsa — en kısası değil — derine arama daha az bellekle sonuç verir.
Özet
- Derine arama bir yolu tıkanana kadar izler, sonra son ayrım noktasına döner; kuyruk yerine yığıt kullanır.
- Özyinelemeli biçim çağrı yığıtını kullanır; açık yığıtlı biçim derin çizgelerde güvenlidir.
- Keşif ve bitiş zamanları düğümler arası soy ilişkisini kodlar; aralıklar ya kapsar ya ayrıktır.
- Döngü tespitinde “ziyaret edildi” ile “hâlâ açık” ayrımı zorunludur.
- Enine arama en kısa yolu bulur, derine arama bulmaz; bellek davranışları çizgenin biçimine göre ayrışır.
- İki gezinmenin de maliyeti ’dir.
Sonraki Adım
Bağımlılık ilişkilerini modelleyen çizgelerde asıl soru şudur: işler hangi sırayla yapılmalıdır? Kursun son dersi, yönlü çevrimsiz çizgelerde geçerli bir yürütme sırası üreten topolojik sıralamayı ele alacak ve bu kursun kurduğu yapıları bir arada kullanacak.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.