Bölüm 12: Kılavuzlu İkili Ağaçlar
Çoktan Seçmeli · Neden Kılavuz?
Soru 1: Üçlü Ağaçta Boş İşaretçi
Her düğümünde üç çocuk işaretçisi bulunan n düğümlü bir ağaçta (n ≥ 1) kaç işaretçi NULL'dır?
A: Toplam 3n işaretçi vardır. Kök dışındaki her düğümü ebeveyninden tam bir işaretçi gösterir: n − 1 dolu. Kalan 3n − (n − 1) = 2n + 1. İkili ağaçta aynı hesap 2n − (n − 1) = n + 1 verir.
Klasik Soru · Neden Kılavuz?
Soru 2: Çağrı Yığını mı, Kılavuz mu?
1.000.000 düğümlü, sola çarpık (her düğümün yalnız sol çocuğu olan) bir ikili ağaç kök ortada geziniliyor. Özyinelemeli gezinmede her çağrı çerçevesi 48 bayt tutuyor. Yığın en çok kaç çerçeveye ve yaklaşık ne kadar belleğe ulaşır? Kılavuzlu ağaçtaki gezinme ne kadar ek bellek ister?
Cevabı göster
- Kökten en soldaki yaprağa kadar 1.000.000 çağrı iç içe açılır, yaprağın NULL sol çocuğuyla bir çağrı daha: 1.000.001 çerçeve, yaklaşık 1.000.001 × 48 ≈ 48 MB.
- Varsayılan yığın tipik olarak 1–8 MB'dır: program yığın taşmasıyla çöker.
- Kendi yığınını tutan döngüsel gezinme de O(h) = 1.000.000 işaretçi (≈ 8 MB, heap'te) ister.
- Kılavuzlu gezinme yalnızca
pişaretçisini kullanır: ek bellek O(1); bedeli düğüm başına iki bayraktır.
Klasik Soru · Kurma Kuralları
Soru 3: Kılavuzları Belirlemek
Kök ortada sırası N L Q O K M P olan ağaç şekildedir (kesikli bağlar henüz yok). Kılavuzlu hâle getirilince hangi işaretçi hangi düğümü gösterir? Kaç kılavuz başlığa gider?
Cevabı göster
| düğüm | sol kılavuz → öncül | sağ kılavuz → ardıl |
|---|---|---|
| N | başlık | L |
| Q | L | O |
| O | (gerçek çocuk Q) | K |
| M | K | (gerçek çocuk P) |
| P | M | başlık |
7 düğüm → 8 = n + 1 kılavuz; 2'si (N'nin solu, P'nin sağı) başlığa gider.
Çoktan Seçmeli · Kurma Kuralları
Soru 4: Başlığı Gösteren Sol Kılavuz
Kılavuzlu bir ağaçta bir düğümün solKilavuz alanı TRUE ve solCocuk alanı başlık düğümünü gösteriyor. Bu düğüm için hangisi kesinlikle doğrudur?
B: Sol kılavuz kök ortada öncülü gösterir; öncül yerine başlık varsa düğümün öncülü yoktur, yani ilk ziyaret edilendir. Bu düğümün sağ alt ağacı olabilir, yani yaprak olmak zorunda değildir; sol alt ağacı olmayan kök de bu düğüm olabilir ama her zaman kök değildir.
Çoktan Seçmeli · Kurma Kuralları
Soru 5: Yalnızca Sağ Kılavuzlar
Bir ağaçta yalnızca sağ NULL işaretçiler kök ortada ardıla çevrilmiş, sol NULL'lar NULL bırakılmıştır (sağ bayraklar tutuluyor). Bu ağaçta O(1) ek bellekle hangisi yapılabilir?
C: kokortada_ardil_bul yalnızca sağ işaretçiyi, sağ bayrağı ve sol çocuk bağlarını kullanır (en sola inerken sol NULL, döngüyü durdurur). Öncül ve ters gezinme sol kılavuzlara gerek duyar; kök sonda ise ebeveyn bilgisi ister.
Hata Bulma · Kurma Kuralları
Soru 6: Bayraksız En Sol
Kılavuzlu ağaçta kök ortada ilk düğümü bulmak için aşağıdaki yordam yazılmıştır. Üçüncü sorudaki ağaçta ne olur? Yordamı düzeltin.
kilavuz_gost en_sol(kilavuz_gost bas) {
kilavuz_gost p = bas->solCocuk; /* kök */
while (p->solCocuk != NULL)
p = p->solCocuk;
return p;
}Cevabı göster
Kılavuzlu ağaçta hiçbir solCocuk NULL değildir: N'nin solu başlığı, başlığın solu yeniden kökü gösterir. p sırasıyla K, L, N, başlık, K, L, N … olur: sonsuz döngü.
Düzeltilmiş gövde:
kilavuz_gost p; if (bas->solKilavuz) return NULL; /* boş ağaç */ p = bas->solCocuk; while (!p->solKilavuz) /* gerçek */ p = p->solCocuk; return p;
Boş ağaçta başlığın solKilavuz'u TRUE'dur; bu durum ayrıca ele alınır. Aynı işi kokortada_ardil_bul(bas) da yapar (boş ağaçta başlığı döndürür).
Çoktan Seçmeli · Kök Ortada Gezinme
Soru 7: Kökün Öncülü
Üçüncü sorudaki kılavuzlu ağaçta kokortada_oncel_bul(K) hangi düğümü döndürür?
kilavuz_gost kokortada_oncel_bul(kilavuz_gost L) {
kilavuz_gost p = L->solCocuk;
if (!L->solKilavuz)
while (!p->sagKilavuz) p = p->sagCocuk;
return p;
}D: K'nin sol işaretçisi gerçek çocuktur (L); sol alt ağacın en sağına inilir: L'nin sağı gerçek (O), O'nun sağı kılavuzdur (sagKilavuz TRUE) → O. Kök ortada sırada da K'den hemen önce O gelir: N L Q O K. Q, O'nun sol alt ağacında olduğu için ondan öncedir.
Adım Adım Çalıştırma · Kök Ortada Gezinme
Soru 8: Yığınsız Kök Ortada Gezinme
Üçüncü sorudaki ağaçta kilavuz_kokortada_dolas(bas) çalışıyor. Her turda p nereye gider, kaç işaretçi izlenir (p'ye yapılan her atama bir sayılır)?
p başlıkta başlar. Yığın ya da özyineleme yok; tek işaretçi yeter.
Başlığın sağı kendisi, bayrağı FALSE → sola in: K, L, N; N'nin solu kılavuz → N (4 işaretçi).
N'nin sağı kılavuz: ardıl doğrudan L.
L'nin sağı gerçek (O); O'nun solu gerçek → Q; Q'nun solu kılavuz → Q.
Q'nun sağ kılavuzu → O.
O'nun sağ kılavuzu → K.
K'nin sağı gerçek (M); M'nin solu kılavuz, döngü hiç dönmez → M.
M'nin sağı gerçek (P); P'nin solu kılavuz → P.
P'nin sağ kılavuzu başlığı gösterir → döngü biter. 12 işaretçi izlendi: n + 1 = 8 çağrı, 4 gerçek sol bağ. O(n), ek bellek O(1).
kilavuz_gost kokortada_ardil_bul(kilavuz_gost L) {
kilavuz_gost p = L->sagCocuk;
if (!L->sagKilavuz)
while (!p->solKilavuz)
p = p->solCocuk;
return p;
}
void kilavuz_kokortada_dolas(kilavuz_gost L) {
kilavuz_gost p = L;
for (;;) {
p = kokortada_ardil_bul(p);
if (p == L) break;
printf("%c ", p->veri);
}
}Çıktı Sorusu · Kök Ortada Gezinme
Soru 9: Kök Önde Kılavuzlu Gezinme
Üçüncü sorudaki ağaçta başlıktan başlanıp kokonde_ardil_bul başlığa dönene kadar çağrılıyor ve her düğüm yazdırılıyor. Çıktı nedir? kokonde_ardil_bul(Q) hangi düğümü döndürür ve bu sırada kaç sağ kılavuz izlenir?
kilavuz_gost kokonde_ardil_bul(kilavuz_gost p) {
if (!p->solKilavuz) /* sol çocuk varsa o */
return p->solCocuk;
while (p->sagKilavuz) /* kılavuzlarla çık */
p = p->sagCocuk;
return p->sagCocuk; /* ilk gerçek sağ */
}Cevabı göster
Çıktı: K L N O Q M P (kök önde sıra).
- Q'nun sol çocuğu yok (sol kılavuz TRUE); sağ kılavuzlarla çıkılır: Q → O (1), O'nun sağı da kılavuz → K (2).
- K'nin sağ işaretçisi gerçek çocuktur: döngü durur ve
K->sagCocuk= M döner. 2 kılavuz izlendi. - Q, O'nun sol alt ağacının son düğümüdür; O'nun sağı boş olduğu için sıra K'nin sağ alt ağacına geçer.
Çoktan Seçmeli · Kök Ortada Gezinme
Soru 10: Morris Gezinmesinin Bedeli
Morris gezinmesi için hangisi doğrudur?
A: Kılavuz, öncülün boş sağ işaretçisine geçici olarak yazılır ve o düğüme ikinci kez gelindiğinde sökülür. Bu yüzden bayrak gerekmez ve gezinme bitince ağaç eski hâlini alır. Gezinme sırasında ağaç değiştiği için aynı anda başka bir okuyucu yanlış bağ görebilir.
Adım Adım Çalıştırma · Kök Ortada Gezinme
Soru 11: Morris Gezinmesi Adım Adım
Aynı ağaç, bu kez kılavuzsuz ve bayraksız tutuluyor. morris_kokortada(kok) hangi geçici kılavuzları kurup söker, ne yazdırır?
Başlangıç: sıradan ağaç, bayrak yok.
K'nin öncülü O (L'den sağa sağa). O'nun sağı boş → geçici kılavuz O → K, sola in.
L'nin öncülü N; kılavuz N → L kurulur, sola in.
N'nin solu yok: yaz, sağa geç; sağ işaretçi geçici kılavuz olduğu için L'ye döner.
Öncül N'nin sağı zaten L: kılavuz sökülür, L yazılır, sağa (O).
O'nun öncülü Q; kılavuz Q → O kurulur, sola in.
Q yazılır; geçici kılavuzla O'ya dönülür.
Q → O sökülür, O yazılır; O'nun sağı (geçici kılavuz) K'ye götürür.
K'nin öncülü O'nun sağı K: kılavuz sökülür, K yazılır, sağa (M).
M'nin solu yok: yaz, sağa (P).
P yazılır, L = NULL: bitti. 10 tur, 3 geçici kılavuz (solu olan her düğüm için bir); ağaç eski hâlinde.
void morris_kokortada(agac_gost L) { while (L) { if (!L->solcocuk) { printf("%c", L->veri); L = L->sagcocuk; } else { agac_gost p = L->solcocuk; while (p->sagcocuk && p->sagcocuk != L) p = p->sagcocuk; if (!p->sagcocuk) { p->sagcocuk = L; L = L->solcocuk; } else { p->sagcocuk = NULL; printf("%c", L->veri); L = L->sagcocuk; } } } }
Kod Yazma · Düğüm Ekleme
Soru 12: Kılavuzlu Arama Ağacında Arama
Kılavuzlu bir ikili arama ağacında (başlık düğümlü, char veri) x değerini arayan kilavuz_gost kilavuz_ara(kilavuz_gost bas, char x) yordamını yazın. Bulunamazsa NULL dönsün; boş ağaç da doğru ele alınsın. Arama, kılavuzlu ağaca ekleme yordamının da ilk adımıdır.
Cevabı göster
kilavuz_gost kilavuz_ara(kilavuz_gost bas, char x) { kilavuz_gost p = bas->solCocuk; short kil = bas->solKilavuz; /* boş: TRUE */ while (!kil) { /* gerçek düğüm */ if (x == p->veri) return p; if (x < p->veri) { kil = p->solKilavuz; p = p->solCocuk; } else { kil = p->sagKilavuz; p = p->sagCocuk; } } return NULL; /* kılavuza çarptı: yok */ }
Sıradan BST'de NULL'a gelince durulurdu; burada izlenen işaretçinin bayrağı TRUE ise (kılavuz) x ağaçta yoktur. Ekleme için tam bu noktada x küçükse sola_ekle, büyükse saga_ekle çağrılır. O(h).
Adım Adım Çalıştırma · Düğüm Ekleme
Soru 13: saga_ekle(L, X): İkinci Durum
Üçüncü sorudaki ağaca saga_ekle(L, X) uygulanıyor. L'nin sağ alt ağacı (O) olduğu için ikinci durumdur. Hangi alanlar değişir, yeni kök ortada sıra nedir?
Önce: L'nin sağı gerçek çocuk O. X yeni düğüm, alanları henüz boş.
X'in sağına L'nin eski sağ alt ağacı (O) gelir; bayrak da kopyalanır: FALSE, gerçek bağ.
X'in kök ortada öncülü L: sol işaretçi L'ye, sol bayrak TRUE (kılavuz).
L → X gerçek bağı kurulur. L'nin bayrağı zaten FALSE idi; birinci durum için bu satır gereklidir.
X'in sağ bayrağı FALSE → X'in ardılı aranır: O'dan en sola, Q. Q'nun sol kılavuzu hâlâ L'yi gösteriyor.
Q'nun öncülü artık X. Yeni sıra: N L X Q O K M P. 7 atama; ardıl araması yüzünden O(h).
void saga_ekle(kilavuz_gost baba, kilavuz_gost cocuk) { kilavuz_gost p; cocuk->sagCocuk = baba->sagCocuk; cocuk->sagKilavuz = baba->sagKilavuz; cocuk->solCocuk = baba; cocuk->solKilavuz = TRUE; baba->sagCocuk = cocuk; baba->sagKilavuz = FALSE; if (!cocuk->sagKilavuz) { p = kokortada_ardil_bul(cocuk); p->solCocuk = cocuk; } }
Çoktan Seçmeli · Düğüm Ekleme
Soru 14: Sabit TRUE Bayrak
saga_ekle'de cocuk->sagKilavuz = baba->sagKilavuz; satırı cocuk->sagKilavuz = TRUE; yapılıyor. Aynı saga_ekle(L, X) çağrısından sonra kök ortada gezinme ne yazdırır?
C: X'in sağ işaretçisi O'yu gösterir ama TRUE bayrağı yüzünden kılavuz sanılır; ardıl(X) doğrudan O olur ve O'nun sol alt ağacındaki Q atlanır. Bayrak TRUE olduğu için if bloğu da çalışmaz; Q'nun sol kılavuzu L'de kalır. Döngü yoktur, gezinme başlığa ulaşıp biter.
Çoktan Seçmeli · Düğüm Ekleme
Soru 15: saga_ekle Neleri Değiştirir?
saga_ekle(baba, cocuk) çağrısında cocuk dışında hangi düğümlerin alanları değişebilir?
D: baba'da yalnız sagCocuk ve sagKilavuz yazılır. İkinci durumda cocuk'un yeni ardılı (baba'nın eski ardılı) eskiden öncül olarak baba'yı gösteriyordu; onun solCocuk'u cocuk yapılır. Başka hiçbir kılavuz cocuk'un hemen öncesini ya da sonrasını göstermediği için değişmez.
Klasik Soru · Düğüm Ekleme
Soru 16: sola_ekle: Birinci Durum
Üçüncü sorudaki ağaca sunumdaki sola_ekle(M, Y) uygulanıyor. M'nin sol alt ağacı yoktur. Y'nin dört alanı ve M'nin sol alanları ne olur? if bloğu çalışır mı? Yeni kök ortada sıra nedir?
void sola_ekle(kilavuz_gost baba, kilavuz_gost cocuk) { cocuk->solCocuk = baba->solCocuk; cocuk->solKilavuz = baba->solKilavuz; cocuk->sagCocuk = baba; cocuk->sagKilavuz = TRUE; baba->solCocuk = cocuk; baba->solKilavuz = FALSE; if (!cocuk->solKilavuz) { kilavuz_gost p = kokortada_oncel_bul(cocuk); p->sagCocuk = cocuk; } }
Cevabı göster
Y->solCocuk = M->solCocuk= K,Y->solKilavuz= TRUE (M'nin eski öncül kılavuzu Y'ye geçer).Y->sagCocuk = M,Y->sagKilavuz = TRUE: Y'nin ardılı M.M->solCocuk = Y,M->solKilavuz = FALSE: gerçek bağ.- Y'nin sol bayrağı TRUE olduğu için if bloğu çalışmaz: Y'den önce gelen K'nin sağı gerçek çocuk (M) olduğundan düzeltilecek kılavuz yoktur.
Yeni sıra: N L Q O K Y M P.