Bölüm 9: Ağaçlar

Veri Yapıları
Ağaç terimleriİkili ağaçlarDolu · tam · mükemmel Dizi ve bağlı gösterimGezinmelerÖzyineleme ve yığınİfade ağacı
Sercan KÜLCÜ · Giresun Üniversitesi · Bilgisayar Mühendisliği

Giriş

Öğrenme Çıktıları

Temel kavramlar

Kök, ebeveyn, çocuk, yaprak, derinlik ve yükseklik terimlerini açıklamak.

Gösterimler

Ağaçları düğüm bağlantıları ve dizilerle temsil etmek.

Gezinmeler

Kök başta, kök ortada, kök sonda ve seviye sırası gezinmeleri uygulamak; özyinelemeyi çağrı yığınıyla izlemek.

Uygulama ve maliyet

Genel ve ikili ağaçları kullanım alanları ve işlem maliyetleriyle karşılaştırmak.

Ağaç Kavramı

Ağaç (Tree)

  • Doğrusal olmayan, hiyerarşik bir veri yapısıdır.
  • Düğümler (node) ve onları bağlayan kenarlardan (edge) oluşur.
  • En üstte tek bir kök (root) bulunur; ağaç kökten aşağı doğru ters çizilir.
  • Kök dışındaki her düğümün tam olarak bir ebeveyni vardır; bu yüzden döngü yoktur.
  • Her düğümün sıfır veya daha fazla çocuğu olabilir.
kökyapraklarkenar
Kural: n düğümlü bir ağaçta her zaman n − 1 kenar vardır (kök hariç her düğüm, ebeveynine tek bir kenarla bağlanır).

Ağaç Kavramı

Günlük Hayatta Ağaçlar: Hiyerarşi

/etcbinhomevarhostsnetworkaliaysenotlar.txtodevfoto.jpg
Dosya sistemiKök dizin, klasörler (iç düğüm), dosyalar (yaprak).
KitapKitap → kısımlar → bölümler → alt başlıklar.
CoğrafyaKıta → ülke → eyalet/il → şehir.
Web sayfasıHTML belgesi iç içe öğelerden oluşan bir ağaçtır (DOM).

Ağaç Kavramı

Ağaç mı?

AHGFBCEDJIKPLMNO

Bu yapı bir ağaç mıdır? 16 düğüm var.

AHGFBCEDJIKPLMNOIDJKMEPNOHLAGBFC

Evet. Bağlantılı, döngüsüz ve 16 düğüme 15 kenar. Herhangi bir düğüm (ör. I) kök seçilip ağaç olarak çizilebilir.

döngü variki ebeveynbağlantısız

Ağaç olmayanlar: döngü içeren, bir düğümü iki ebeveynli olan veya parçaları bağlantısız yapılar.

Ağaç Kavramı

Temel Unsurlar: Kök, İç Düğüm, Yaprak

Kök düğüm (root)Ağacın en üst düğümü; ebeveyni yoktur.dosya sistemi: kök dizin /
İç düğüm (internal node)En az bir çocuğu olan düğüm.dosya sistemi: klasörler
Yaprak (leaf)Hiç çocuğu olmayan düğüm; dış düğüm de denir.dosya sistemi: dosyalar
12934567kökiç düğümyapraklar: 9, 4, 5, 6, 7

Kök de (çocuğu varsa) bir iç düğümdür. Tek düğümlü ağaçta kök aynı zamanda yapraktır.

Ağaç Kavramı

Ağaç İlişkileri

TerimAnlamı (sağdaki ağaçta)
Ebeveyn (parent)Hemen üstteki düğüm: D, H'nin ebeveyni
Çocuk (child)Hemen alttaki düğüm: H, I, J → D'nin çocukları
Kardeş (sibling)Ebeveyni aynı olanlar: H, I, J
Ata (ancestor)Köke giden yoldaki düğümler: M'nin ataları H, D, A
Soy (descendant)Alt ağaçtaki düğümler: D'nin soyu H, I, J, M
ABCDEFGHIJKLM
Dikkat: Aynı seviyede olmak kardeş olmak demek değildir. F ve G aynı derinlikte ama ebeveynleri farklı (B ve C) → kardeş değiller.

Ağaç Kavramı

Terimler Ağaç Üzerinde

d=0d=1d=2d=3ABCDEFGHIJKLM

Kök: ebeveyni olmayan tek düğüm → A.

d=0d=1d=2d=3ABCDEFGHIJKLM

Ebeveyn / çocuk: D, H, I ve J'nin ebeveynidir; H, I, J de D'nin çocuklarıdır.

d=0d=1d=2d=3ABCDEFGHIJKLM

Kardeşler: H, I, J (ebeveynleri D). F ile G kardeş değildir.

d=0d=1d=2d=3ABCDEFGHIJKLM

Yapraklar: K, L, F, G, M, I, J (çocuksuz düğümler).

d=0d=1d=2d=3ABCDEFGHIJKLM

İç düğümler: A, B, C, D, E, H (en az bir çocuğu olanlar).

d=0d=1d=2d=3ABCDEFGHIJKLM

Atalar: M'nin ataları H, D, A. Tersine M; H, D ve A'nın soyundandır.

d=0d=1d=2d=3ABCDEFGHIJKLM321321

Derece (degree) = çocuk sayısı: A 3, B 2, C 1, D 3 … Ağacın derecesi = en büyük derece = 3.

d=0d=1d=2d=3ABCDEFGHIJKLM

Derinlik (depth): kökten düğüme kenar sayısı. E'nin derinliği 2 (A→B→E).

d=0d=1d=2d=3ABCDEFGHIJKLM

Yükseklik (height): kökten en uzak yaprağa kenar sayısı = 3 (A→B→E→K).

d=0d=1d=2d=3ABCDEFGHIJKLM

Alt ağaç (subtree): D ve tüm soyu (H, I, J, M) kendi başına bir ağaçtır.

Ağaç Kavramı

Derece, Derinlik, Yükseklik

ÖlçüTanımÖnceki ağaçta
Derece (degree)Bir düğümün çocuk sayısı (alt ağaç sayısı)D → 3
Derinlik (depth)Kökten o düğüme kadar olan yoldaki kenar sayısı; kökün derinliği 0E → 2
Seviye (level)Aynı derinlikteki düğümlerin kümesiseviye 2: E … J
Düğüm yüksekliğiDüğümden altındaki en uzak yaprağa kenar sayısı; yaprağın yüksekliği 0D → 2
Ağacın yüksekliğiKökün yüksekliği = en büyük derinlik3
Bu derste yükseklik ve derinlik kenar sayısı ile ölçülür. Bazı kaynaklar düğüm sayısını kullanır (seviyeleri 1'den başlatır); o zaman tüm değerler 1 fazla çıkar. Hangi tanımın kullanıldığına dikkat edin.

Ağaç Kavramı

Derinlik ve Yükseklik

ABCDEFGHIJK
Ağacın yüksekliği = kökün yüksekliği = 3 (en uzun yol A→E→J→K). En derin düğüm K'nin derinliği de 3'tür.
DüğümYükseklikDerinlik
A30
B11
C01
D11
E21
F02
G02
H02
I02
J12
K03

Ağaç Kavramı

Yol ve Alt Ağaç

  • Yol (path): ardışık düğümleri kenarlarla bağlayan dizi.
    p = (v₀, e₁, v₁, …, ek, vk)
  • start(p) = v₀, end(p) = vk, length(p) = k (kenar sayısı).
  • Ağaçta iki düğüm arasında tam olarak bir basit yol vardır; ikinci bir yol olsaydı döngü oluşurdu.
  • Alt ağaç (subtree): bir düğüm ve onun tüm soyu; kendisi de bir ağaçtır. Ör. bir klasör ve altındaki her şey.
ABCDEFGHIJKLM
Vurgulu yol: K → E → B → A → D → H → M, uzunluğu 6. Bu iki düğüm arasında başka yol yoktur.

Ağaç Kavramı

Temel Ağaç Türleri

TürÖzellik
Genel ağaçBir düğümün çocuk sayısına sınır yoktur.
k-lı ağaç (k-ary)Her düğümün en fazla k çocuğu vardır.
İkili ağaç (binary)Her düğümün en fazla iki çocuğu vardır: sol ve sağ.
İkili arama ağacı (BST)İkili ağaç + her düğümde: sol alt ağaçtaki anahtarlar küçük, sağdakiler büyük.
genel ağaç3-lü ağaç (k = 3)ikili ağaç83101614ikili arama ağacı

Ağaç Kavramı

Ağaç Soyut Veri Tipi (Tree ADT)

public interface Agac<E> extends Iterable<E> {
  Konum<E> kok();
  Konum<E> ebeveyn(Konum<E> p);
  Iterable<Konum<E>> cocuklar(Konum<E> p);
  int cocukSayisi(Konum<E> p);
  boolean icMi(Konum<E> p);      // isInternal
  boolean yaprakMi(Konum<E> p);  // isExternal
  boolean kokMu(Konum<E> p);     // isRoot
  int size();
  boolean isEmpty();
  Iterable<Konum<E>> konumlar(); // positions
}
// Konum<E> (Position): E getElement();

İkili ağaç ADT'si bunlara sol(p), sag(p), kardes(p) ekler (Goodrich: left, right, sibling).

ABCDEFGebeveyn(p)pcocuklar(p): D, Eyaprakkök

Konum (position), düğümün kendisini gizleyen bir "yer" soyutlamasıdır: kullanıcı yalnızca öğeye ve ADT metotlarına erişir.

Ağaç Kavramı · Kodu adım adım çalıştır

Kod İzleme: ADT ile derinlik(G) ve yukseklik(B)

ABCDEFGşimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

derinlik(G): G kök değil → ebeveyni E için derinlik(E) çağrılır (yukarı çıkılır).

ABCDEFGşimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

derinlik(E): E kök değil → ebeveyni B için derinlik(B) çağrılır (yukarı çıkılır).

ABCDEFGşimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

derinlik(B): B kök değil → ebeveyni A için derinlik(A) çağrılır (yukarı çıkılır).

ABCDEFG↑ 0şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

derinlik(A): A kök → return 0. Taban durum; artık çerçeveler geri dönmeye başlar.

ABCDEFG↑ 0↑ 1şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

derinlik(B) = 1 + 0 = 1 döner.

ABCDEFG↑ 0↑ 1↑ 2şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

derinlik(E) = 1 + 1 = 2 döner.

ABCDEFG↑ 0↑ 1↑ 2↑ 3şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

derinlik(G) = 1 + 2 = 3 döner. G'nin derinliği 3: kökten G'ye 3 kenar (A–B–E–G). Maliyet O(d + 1).

ABCDEFGşimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

Şimdi yukseklik(B): aşağı doğru, çocuklar üzerinden özyineleme (derinlik yukarı, yükseklik aşağı bakar).

ABCDEFGşimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yukseklik(B): h = 0. Çocuklar: D, E. İlk çocuk D için özyineleme.

ABCDEFG↑ 0şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yukseklik(D): h = 0; D'nin çocuğu yok, döngü hiç dönmez → return 0 (yaprak).

ABCDEFG↑ 0şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

D'den 0 geldi: h = max(0, 1 + 0) = 1. Sıradaki çocuk: E.

ABCDEFG↑ 0şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yukseklik(E): h = 0. Çocuklar: G. İlk çocuk G için özyineleme.

ABCDEFG↑ 0↑ 0şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yukseklik(G): h = 0; G'nin çocuğu yok, döngü hiç dönmez → return 0 (yaprak).

ABCDEFG↑ 0↑ 0↑ 1şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

G'den 0 geldi: h = max(0, 1 + 0) = 1. Çocuk kalmadı → return 1.

ABCDEFG↑ 0↑ 0↑ 1↑ 2şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

E'den 1 geldi: h = max(1, 1 + 1) = 2. Çocuk kalmadı → return 2. Yükseklik(B) = 2 (B–E–G); her düğüm bir kez ziyaret edilir.

int derinlik(Konum<E> p) {
    if (kokMu(p)) return 0;
    return 1 + derinlik(ebeveyn(p));
}
int yukseklik(Konum<E> p) {
    int h = 0;
    for (Konum<E> c : cocuklar(p))
        h = Math.max(h, 1 + yukseklik(c));
    return h;
}

İkili Ağaçlar

İkili Ağaç (Binary Tree)

  • Her düğümün en fazla iki çocuğu vardır: sol çocuk ve sağ çocuk.
  • Çocukların yeri önemlidir: yalnızca sol çocuğu olan ağaç, yalnızca sağ çocuğu olandan farklıdır.
  • Özyinelemeli tanım: İkili ağaç ya boştur ya da bir kök ile iki ikili ağaçtan (sol ve sağ alt ağaç) oluşur.
ABAB≠
ABCDABCDEFGHIJK

Soldaki zincir de geçerli bir ikili ağaçtır (çarpık / skewed ağaç): düğümler dengeli dağılmak zorunda değildir.

İkili Ağaçlar

Dolu, Tam ve Mükemmel

Dolu ikili ağaç (full)Her düğümün ya 0 ya da 2 çocuğu vardır; tek çocuklu düğüm yoktur.
Tam ikili ağaç (complete)Son seviye hariç tüm seviyeler doludur; son seviye soldan sağa boşluksuz dolar.
Mükemmel ikili ağaç (perfect)Tüm iç düğümlerin 2 çocuğu var ve tüm yapraklar aynı derinlikte.
Mükemmel ağaç hem dolu hem tamdır; yüksekliği h ise 2h+1 − 1 düğümü vardır. Türkçe kaynaklarda "tam" ve "dolu" bazen ters kullanılır; İngilizce karşılıklar (full / complete / perfect) esas alınmalıdır.

İkili Ağaçlar

Hangisi? Dolu mu, Tam mı, Mükemmel mi?

ABCDEHI
Dolu (full)evet
Tam (complete)hayır
Mükemmel (perfect)hayır

Her düğümün 0 ya da 2 çocuğu var → dolu. Ama C'nin altı boşken en alt seviye E'nin altında → tam değil.

12345678910
Dolu (full)hayır
Tam (complete)evet
Mükemmel (perfect)hayır

Son seviye (8, 9, 10) soldan sağa boşluksuz → tam. 5'in tek çocuğu (10) var → dolu değil.

12345678911
Dolu (full)hayır
Tam (complete)hayır
Mükemmel (perfect)hayır

5'in tek çocuğu var → dolu değil. 10. konum boşken 11 dolu → tam değil. Ne tam ne dolu.

1234567
Dolu (full)evet
Tam (complete)evet
Mükemmel (perfect)evet

Tüm iç düğümlerin 2 çocuğu var, tüm yapraklar aynı derinlikte → mükemmel (dolayısıyla dolu ve tam).

İkili Ağaçlar

İkili Ağaç Özellikleri

ÖzellikFormülÖrnek
d derinliğindeki en fazla düğüm2dd = 3 → en fazla 8 düğüm
Yüksekliği h olan ağaçta en fazla düğüm2h+1 − 1h = 3 → 15 (mükemmel ağaç)
Yüksekliği h olan ağaçta en az düğümh + 1çarpık (zincir) ağaç
n düğümlü ağacın yüksekliği⌊log2 n⌋ ≤ h ≤ n − 1n = 15 → 3 ≤ h ≤ 14
n düğümlü ağaçtaki kenar sayısın − 1her düğümün tek ebeveyni
Dolu ikili ağaçta yaprak sayısıiç düğüm + 17 düğüm → 3 iç, 4 yaprak
Yükseklik, ağaç işlemlerinin maliyetini belirler: dengeli bir ağaçta h ≈ log2 n (1 milyon düğüm → ≈ 20 seviye), çarpık ağaçta h = n − 1.

İkili Ağaçlar · Adım adım

Dolu İkili Ağaçta Neden Yaprak = İç Düğüm + 1?

Yiç düğüm i = 0yaprak y = 1y − i = 1

Tek düğümlü ağaç: kök bir yapraktır (Y). i = 0, y = 1 → y = i + 1.

İYYiç düğüm i = 1yaprak y = 2y − i = 1

Bir yaprağa iki çocuk eklendi (dolu kalması için 0 ya da 2 çocuk): o yaprak iç düğüm olur (i + 1), iki yeni yaprak gelir (y − 1 + 2 = y + 1). Fark değişmez.

İYİYYiç düğüm i = 2yaprak y = 3y − i = 1

Bir yaprağa iki çocuk eklendi (dolu kalması için 0 ya da 2 çocuk): o yaprak iç düğüm olur (i + 1), iki yeni yaprak gelir (y − 1 + 2 = y + 1). Fark değişmez.

İYYİYYİiç düğüm i = 3yaprak y = 4y − i = 1

Bir yaprağa iki çocuk eklendi (dolu kalması için 0 ya da 2 çocuk): o yaprak iç düğüm olur (i + 1), iki yeni yaprak gelir (y − 1 + 2 = y + 1). Fark değişmez.

YYİİYYİYİiç düğüm i = 4yaprak y = 5y − i = 1

Her genişletme i'yi de y'yi de 1 artırır; başlangıçta y − i = 1 olduğundan her dolu ikili ağaçta y = i + 1 (tümevarım). Sonuç: n = 2i + 1 → n her zaman tek.

İ: iç düğüm, Y: yaprak; turuncu: son adımda eklenen yapraklar. Bu özellik ifade ağaçlarında (her işleç 2 işlenen) ve Huffman ağaçlarında kullanılır.

Gösterimler

Dizi Gösterimi

Düğümler seviye seviye, soldan sağa diziye yerleştirilir. Kök 1 tabanlı dizide indis 1'de, 0 tabanlıda 0'dadır. İndis i'deki düğüm için:

1 tabanlı0 tabanlı
Sol çocuk2i2i + 1
Sağ çocuk2i + 12i + 2
Ebeveyn⌊i / 2⌋⌊(i − 1) / 2⌋

Örnek: E (i = 5) → çocuklar 10 ve 11 (boş), ebeveyn ⌊5/2⌋ = 2 (B).

ABCDEFGHI1234567890A1B2C3D4E5F6G7H8I9

Referans tutulmaz; ebeveyn/çocuk erişimi O(1) aritmetikle yapılır. Tam ikili ağaçlar için idealdir (ör. heap).

Gösterimler · Kodu adım adım çalıştır

Kod İzleme: Dizi Gösteriminde İndis Hesabı

ABCDEFGHI123456789dizi a (n = 9)0A1B2C3D4E5F6G7H8I91011yok (> n)

sol(2) = 2·2 = 4 → a[4] = D, B'nin sol çocuğu (dizi 1 tabanlı, a[0] boş). Referans yok; konum aritmetikle bulunur.

ABCDEFGHI123456789dizi a (n = 9)0A1B2C3D4E5F6G7H8I91011yok (> n)

sag(2) = 2·2 + 1 = 5 → a[5] = E. Sağ çocuk her zaman sol çocuğun hemen yanındadır.

ABCDEFGHI123456789dizi a (n = 9)0A1B2C3D4E5F6G7H8I91011yok (> n)

ebeveyn(2) = 2 / 2 = 1 → a[1] = A (kök).

ABCDEFGHI123456789dizi a (n = 9)0A1B2C3D4E5F6G7H8I91011yok (> n)

D (i = 4): çocuklar 8 → H ve 9 → I.

ABCDEFGHI123456789dizi a (n = 9)0A1B2C3D4E5F6G7H8I91011yok (> n)

E (i = 5): 10 ve 11 > n = 9 → dizinin dışında, yani E'nin çocuğu yok (yaprak). Kontrol: 2i ≤ n.

ABCDEFGHI123456789dizi a (n = 9)0A1B2C3D4E5F6G7H8I91011yok (> n)

ebeveyn(9) = 9 / 2 = 4: tamsayı bölmesi aşağı yuvarlar (⌊4,5⌋ = 4) → D. 8 ve 9 kardeş olduğundan ikisi de 4'ü verir.

ABCDEFGHI123456789dizi a (n = 9)0A1B2C3D4E5F6G7H8I91011yok (> n)

kokeYol(a, 9): I'dan köke kadar ebeveyn zinciri izlenecek.

ABCDEFGHI123456789dizi a (n = 9)0A1B2C3D4E5F6G7H8I91011yok (> n)

9 ≥ 1 → döngü sürer; a[9] = I yazdırılır.

ABCDEFGHI123456789dizi a (n = 9)0A1B2C3D4E5F6G7H8I91011yok (> n)

i = ebeveyn(9) = 4 → D.

ABCDEFGHI123456789dizi a (n = 9)0A1B2C3D4E5F6G7H8I91011yok (> n)

4 ≥ 1 → döngü sürer; a[4] = D yazdırılır.

ABCDEFGHI123456789dizi a (n = 9)0A1B2C3D4E5F6G7H8I91011yok (> n)

i = ebeveyn(4) = 2 → B.

ABCDEFGHI123456789dizi a (n = 9)0A1B2C3D4E5F6G7H8I91011yok (> n)

2 ≥ 1 → döngü sürer; a[2] = B yazdırılır.

ABCDEFGHI123456789dizi a (n = 9)0A1B2C3D4E5F6G7H8I91011yok (> n)

i = ebeveyn(2) = 1 → A.

ABCDEFGHI123456789dizi a (n = 9)0A1B2C3D4E5F6G7H8I91011yok (> n)

1 ≥ 1 → döngü sürer; a[1] = A yazdırılır.

ABCDEFGHI123456789dizi a (n = 9)0A1B2C3D4E5F6G7H8I91011yok (> n)

i = ebeveyn(1) = 0 (kökün ebeveyni yok).

ABCDEFGHI123456789dizi a (n = 9)0A1B2C3D4E5F6G7H8I91011yok (> n)

0 ≥ 1 yanlış → döngü biter. Çıktı: I D B A. Her adım indisi yarıya indirir → O(log n) (derinlik kadar).

int sol(int i)     { return 2 * i; }
int sag(int i)     { return 2 * i + 1; }
int ebeveyn(int i) { return i / 2; }
void kokeYol(char[] a, int i) {  // i'den köke
  while (i >= 1) {
    System.out.print(a[i] + " ");
    i = ebeveyn(i);
  }
}

Gösterimler

Dizide Bellek İsrafı

ABCDE124816
  • Çarpık ağaçta düğümlerin indisleri katlanarak büyür: 1, 2, 4, 8, 16.
  • 5 düğüm için 16 hücre gerekir; 11 hücre boş kalır. Sağa çarpık olsaydı indisler 1, 3, 7, 15, 31 olurdu → 31 hücre.
  • Genel olarak n düğümlü bir ağaç 2n − 1 hücreye kadar yer isteyebilir.
A1B23C4567D89101112131415E16

Dizi gösterimi

  • Referans yok, hızlı indis hesabı
  • Tam ağaçlarda boşluksuz

Ama

  • Seyrek/çarpık ağaçta büyük israf
  • Boyut sabit; büyütmek için kopyalama

Gösterimler

Bağlı Gösterim (Linked Representation)

  • Her ağaç düğümü bir nesnedir: veri + sol ve sağ çocuk referansı.
  • Çocuk yoksa referans null'dır.
  • Boyut dinamiktir; yalnızca var olan düğümler için bellek ayrılır.
  • Bir düğüme ulaşmak için kökten başlayıp referansları izlemek gerekir.
solverisagsol alt ağaçsağ alt ağaç
public class AgacDugumu {
    int veri;
    AgacDugumu sol;   // sol çocuk (yoksa null)
    AgacDugumu sag;   // sağ çocuk (yoksa null)

    public AgacDugumu(int veri) {
        this.veri = veri;   // sol = sag = null
    }
}
// 9 kökünde küçük bir ağaç kuralım
AgacDugumu kok = new AgacDugumu(9);
kok.sol = new AgacDugumu(2);
kok.sag = new AgacDugumu(3);
kok.sol.sol = new AgacDugumu(4);

Gösterimler

Bağlı Gösterim: Örnek

ABCDEFGçapraz çizgi = null referans
7 düğüm14 referans alanı: 6'sı dolu (kenar sayısı n − 1), 8'i null.
Genel kuraln düğümlü ikili ağaçta her zaman n + 1 null referans vardır.
Ebeveyne çıkışGerekirse düğüme bir ebeveyn referansı da eklenir.

Gösterimler

Dizi mi, Bağlı mı?

ÖlçütDizi gösterimiBağlı gösterim
BellekTam ağaçta en az; seyrek ağaçta 2n − 1'e kadar israfDüğüm başına 2 ek referans; israf yok
Çocuk / ebeveyn erişimiO(1), indis aritmetiğiyleÇocuk O(1); ebeveyn için ek referans gerekir
i. seviyedeki k. düğümO(1): indis 2i + k − 1 (1 tabanlı, k ≥ 1)Kökten gezinme gerekir
BüyümeDizi dolunca kopyalanarak büyütülürYeni düğüm eklemek O(1) (konum biliniyorsa)
Uygun olduğu yerTam ikili ağaçlar (heap)Genel ve değişken şekilli ağaçlar (BST, ifade ağacı)
Kural: ağacın şekli tam kalıyorsa dizi, şekli öngörülemiyorsa bağlı gösterim tercih edilir.

Gösterimler

Genel Ağaç Gösterimi

Çocuk sayısı sınırsız olduğunda iki yaygın yol vardır:

// 1) Çocuk listesi
class GenelDugum {
    int veri;
    List<GenelDugum> cocuklar
        = new ArrayList<>();
}
// 2) İlk çocuk – sonraki kardeş
class KardesDugum {
    int veri;
    KardesDugum ilkCocuk;
    KardesDugum sonrakiKardes;
}

İkinci yolda her düğüm yine iki referans tutar: ilk çocuk (aşağı) ve sonraki kardeş (sağa). Böylece her genel ağaç bir ikili ağaç gibi saklanabilir.

ABCDEFGABCDEFG

Solda genel ağaç; sağda ilk çocuk (düz ok) – sonraki kardeş (kesikli ok) gösterimi.

Gezinmeler

Ağaç Gezinmeleri

Gezinme: Her düğümü bir kez ziyaret eder. Derinlik öncelikli (DFS) gezinmeler kökün ziyaret zamanına göre; seviye sırası (BFS) ise seviyelere göre ilerler.
1234567
GezinmeSıraÇıktıTipik kullanım
Kök başta (preorder)kök → sol → sağ1 2 4 5 3 6 7Ağacı kopyalamak, önek ifade
Kök ortada (inorder)sol → kök → sağ4 2 5 1 6 3 7BST'yi sıralı gezinmek
Kök sonda (postorder)sol → sağ → kök4 5 2 6 7 3 1Silme, boyut/yükseklik hesabı
Seviye sırası (level-order)seviye seviye, soldan sağa1 2 3 4 5 6 7Seviye bazlı işlemler

Gezinmeler

Kök Başta Gezinme (Preorder)

  1. Kökü ziyaret et.
  2. Sol alt ağacı kök başta gez.
  3. Sağ alt ağacı kök başta gez.

Kullanım: ağacı kopyalamak, düğümleri diziye yazmak, önek (prefix) ifade.

ziyaret(kok);
kokBasta(kok.sol);
kokBasta(kok.sag);
1234567Çıktı: 1şimdiziyaret edildibekliyor

Kök 1 ziyaret edilir; sonra sol alt ağaca geçilir.

1234567Çıktı: 1 2şimdiziyaret edildibekliyor

2 ziyaret edilir; sonra onun sol alt ağacı.

1234567Çıktı: 1 2 4şimdiziyaret edildibekliyor

4 yaprak: ziyaret edilir, çocuğu yok.

1234567Çıktı: 1 2 4 5şimdiziyaret edildibekliyor

2'nin sağ alt ağacı: 5.

1234567Çıktı: 1 2 4 5 3şimdiziyaret edildibekliyor

Sol alt ağaç bitti; 1'in sağ alt ağacı: 3.

1234567Çıktı: 1 2 4 5 3 6şimdiziyaret edildibekliyor

3'ün sol çocuğu 6.

1234567Çıktı: 1 2 4 5 3 6 7şimdiziyaret edildibekliyor

3'ün sağ çocuğu 7. Çıktı: 1 2 4 5 3 6 7

Gezinmeler

Kök Ortada Gezinme (Inorder)

  1. Sol alt ağacı kök ortada gez.
  2. Kökü ziyaret et.
  3. Sağ alt ağacı kök ortada gez.

Kullanım: ikili arama ağacında anahtarları küçükten büyüğe sıralı vermek, ara ek (infix) ifade.

kokOrtada(kok.sol);
ziyaret(kok);
kokOrtada(kok.sag);
1234567Çıktı: 4şimdiziyaret edildibekliyor

Kökten hep sola inilir; ilk ziyaret en soldaki düğüm: 4.

1234567Çıktı: 4 2şimdiziyaret edildibekliyor

4'ün alt ağacı bitti → ebeveyni 2.

1234567Çıktı: 4 2 5şimdiziyaret edildibekliyor

2'nin sağ alt ağacı: 5.

1234567Çıktı: 4 2 5 1şimdiziyaret edildibekliyor

Sol alt ağaç tamamlandı → kök 1.

1234567Çıktı: 4 2 5 1 6şimdiziyaret edildibekliyor

Sağ alt ağaçta yine en sola inilir: 6.

1234567Çıktı: 4 2 5 1 6 3şimdiziyaret edildibekliyor

6'dan sonra ebeveyni 3.

1234567Çıktı: 4 2 5 1 6 3 7şimdiziyaret edildibekliyor

Son olarak 7. Çıktı: 4 2 5 1 6 3 7

Gezinmeler

Kök Sonda Gezinme (Postorder)

  1. Sol alt ağacı kök sonda gez.
  2. Sağ alt ağacı kök sonda gez.
  3. Kökü ziyaret et.

Kullanım: ağacı silmek (önce çocuklar), boyut/yükseklik hesabı, sonek (postfix) ifade.

kokSonda(kok.sol);
kokSonda(kok.sag);
ziyaret(kok);
1234567Çıktı: 4şimdiziyaret edildibekliyor

En soldaki yaprak 4 ilk ziyaret edilir.

1234567Çıktı: 4 5şimdiziyaret edildibekliyor

Sonra 2'nin sağ çocuğu 5.

1234567Çıktı: 4 5 2şimdiziyaret edildibekliyor

2'nin iki alt ağacı da bitti → 2.

1234567Çıktı: 4 5 2 6şimdiziyaret edildibekliyor

1'in sağ alt ağacı: önce 6.

1234567Çıktı: 4 5 2 6 7şimdiziyaret edildibekliyor

Sonra 7.

1234567Çıktı: 4 5 2 6 7 3şimdiziyaret edildibekliyor

3'ün çocukları bitti → 3.

1234567Çıktı: 4 5 2 6 7 3 1şimdiziyaret edildibekliyor

Kök en son ziyaret edilir: 1. Çıktı: 4 5 2 6 7 3 1

Gezinmeler · Adım adım

Üç Gezinme, Tek Tur: Euler Turu

ABCDE

Ağacın etrafında, kökün solundan başlayıp kenarlara sol elimizle dokunarak yürüyelim (Euler turu). Her düğüme üç kez uğranır: solundan, altından, sağından.

ABCDE12345Sol işaret → Kök başta (preorder):A B D E C

Bir düğümü soldan geçerken yazarsak (ilk karşılaşma) kök başta sırası çıkar: A B D E C.

ABCDE1234512345Sol işaret → Kök başta (preorder):A B D E CAlt işaret → Kök ortada (inorder):D B E A C

Altından geçerken (sol alt ağaç bitmiş, sağ başlamamış) yazarsak kök ortada sırası çıkar: D B E A C.

ABCDE123451234512345Sol işaret → Kök başta (preorder):A B D E CAlt işaret → Kök ortada (inorder):D B E A CSağ işaret → Kök sonda (postorder):D E B C A

Sağından geçerken (iki alt ağaç da bitmiş) yazarsak kök sonda sırası çıkar: D E B C A. Üç gezinme aynı turun farklı anlarıdır; tur O(n) sürer.

Gezinmeler

Seviye Sırası Gezinme (Level-order)

  • Kökten başlar, her seviyeyi soldan sağa tarar, sonra bir alt seviyeye iner.
  • Genişlik öncelikli aramanın (BFS) ağaçtaki hâlidir.
  • Özyineleme yerine bir kuyruk (FIFO) kullanır: önce gelen düğümün çocukları önce işlenir.

Kullanım: seviye bazlı işlemler (her seviyenin toplamı, en yakın yaprak), ağacı seviye seviye yazdırmak.

seviye 0seviye 1seviye 21234567Çıktı: 1 2 3 4 5 6 7

Gezinmeler · Kodu adım adım çalıştır

Özyinelemeli Kök Başta ve Çağrı Yığını

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokBasta(9) çağrıldı (kök). null değil → önce kök yazdırılır: 9, sonra alt ağaçlar.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokBasta(2) çağrıldı (9'un sol çocuğu). null değil → önce kök yazdırılır: 2, sonra alt ağaçlar.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokBasta(4) çağrıldı (2'nin sol çocuğu). null değil → önce kök yazdırılır: 4, sonra alt ağaçlar.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokBasta(4.sol) = kokBasta(null): taban durum, hemen return. Boş alt ağaçta yapılacak iş yok.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokBasta(4.sag) = kokBasta(null): taban durum, hemen return. Boş alt ağaçta yapılacak iş yok.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokBasta(4) bitti (satır 8); çerçeve yığından çıkar, kokBasta(2)'ye dönülür.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokBasta(2.sag) = kokBasta(null): taban durum, hemen return. Boş alt ağaçta yapılacak iş yok.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokBasta(2) bitti (satır 8); çerçeve yığından çıkar, kokBasta(9)'a dönülür.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokBasta(3) çağrıldı (9'un sağ çocuğu). null değil → önce kök yazdırılır: 3, sonra alt ağaçlar.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokBasta(3.sol) = kokBasta(null): taban durum, hemen return. Boş alt ağaçta yapılacak iş yok.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokBasta(3.sag) = kokBasta(null): taban durum, hemen return. Boş alt ağaçta yapılacak iş yok.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokBasta(3) bitti (satır 8); çerçeve yığından çıkar, kokBasta(9)'a dönülür.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokBasta(9) bitti (satır 8); yığın boşalır. Çıktı: 9 2 4 3 — her düğüm bir kez, en fazla h + 2 = 4 çerçeve.

public void kokBasta(AgacDugumu kok) {
  if (kok == null) {
    return;
  }
  System.out.print(kok.veri + " ");
  kokBasta(kok.sol);
  kokBasta(kok.sag);
}

Gezinmeler · Kodu adım adım çalıştır

Özyinelemeli Kök Ortada ve Çağrı Yığını

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokOrtada(9) çağrıldı (kök). 9 henüz yazdırılmaz: önce sol alt ağaç gezilmeli.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokOrtada(2) çağrıldı (9'un sol çocuğu). 2 henüz yazdırılmaz: önce sol alt ağaç gezilmeli.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokOrtada(4) çağrıldı (2'nin sol çocuğu). 4 henüz yazdırılmaz: önce sol alt ağaç gezilmeli.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokOrtada(4.sol) = kokOrtada(null): taban durum, hemen return. Boş alt ağaçta yapılacak iş yok.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

Sol alt ağaç bitti, kokOrtada(4)'e dönüldü → 4 yazdırılır. Sırada sağ alt ağaç var.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokOrtada(4.sag) = kokOrtada(null): taban durum, hemen return. Boş alt ağaçta yapılacak iş yok.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokOrtada(4) bitti (satır 8); çerçeve yığından çıkar, kokOrtada(2)'ye dönülür.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

Sol alt ağaç bitti, kokOrtada(2)'ye dönüldü → 2 yazdırılır. Sırada sağ alt ağaç var.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokOrtada(2.sag) = kokOrtada(null): taban durum, hemen return. Boş alt ağaçta yapılacak iş yok.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokOrtada(2) bitti (satır 8); çerçeve yığından çıkar, kokOrtada(9)'a dönülür.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

Sol alt ağaç bitti, kokOrtada(9)'a dönüldü → 9 yazdırılır. Sırada sağ alt ağaç var.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokOrtada(3) çağrıldı (9'un sağ çocuğu). 3 henüz yazdırılmaz: önce sol alt ağaç gezilmeli.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokOrtada(3.sol) = kokOrtada(null): taban durum, hemen return. Boş alt ağaçta yapılacak iş yok.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

Sol alt ağaç bitti, kokOrtada(3)'e dönüldü → 3 yazdırılır. Sırada sağ alt ağaç var.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokOrtada(3.sag) = kokOrtada(null): taban durum, hemen return. Boş alt ağaçta yapılacak iş yok.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokOrtada(3) bitti (satır 8); çerçeve yığından çıkar, kokOrtada(9)'a dönülür.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokOrtada(9) bitti (satır 8); yığın boşalır. Çıktı: 4 2 9 3 — her düğüm bir kez, en fazla h + 2 = 4 çerçeve.

public void kokOrtada(AgacDugumu kok) {
  if (kok == null) {
    return;
  }
  kokOrtada(kok.sol);
  System.out.print(kok.veri + " ");
  kokOrtada(kok.sag);
}

Gezinmeler · Kodu adım adım çalıştır

Özyinelemeli Kök Sonda ve Çağrı Yığını

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokSonda(9) çağrıldı (kök). Kök en sona kalır: önce sol alt ağaç.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokSonda(2) çağrıldı (9'un sol çocuğu). Kök en sona kalır: önce sol alt ağaç.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokSonda(4) çağrıldı (2'nin sol çocuğu). Kök en sona kalır: önce sol alt ağaç.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokSonda(4.sol) = kokSonda(null): taban durum, hemen return. Boş alt ağaçta yapılacak iş yok.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokSonda(4.sag) = kokSonda(null): taban durum, hemen return. Boş alt ağaçta yapılacak iş yok.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokSonda(4): iki alt ağaç da bitti → şimdi 4 yazdırılır.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokSonda(4) bitti (satır 8); çerçeve yığından çıkar, kokSonda(2)'ye dönülür.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokSonda(2.sag) = kokSonda(null): taban durum, hemen return. Boş alt ağaçta yapılacak iş yok.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokSonda(2): iki alt ağaç da bitti → şimdi 2 yazdırılır.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokSonda(2) bitti (satır 8); çerçeve yığından çıkar, kokSonda(9)'a dönülür.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokSonda(3) çağrıldı (9'un sağ çocuğu). Kök en sona kalır: önce sol alt ağaç.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokSonda(3.sol) = kokSonda(null): taban durum, hemen return. Boş alt ağaçta yapılacak iş yok.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokSonda(3.sag) = kokSonda(null): taban durum, hemen return. Boş alt ağaçta yapılacak iş yok.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokSonda(3): iki alt ağaç da bitti → şimdi 3 yazdırılır.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokSonda(3) bitti (satır 8); çerçeve yığından çıkar, kokSonda(9)'a dönülür.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokSonda(9): iki alt ağaç da bitti → şimdi 9 yazdırılır.

nullnullnullnullnull9234şimdi çalışançağrı yığınındayazdırıldıhenüz yazdırılmadı

kokSonda(9) bitti (satır 8); yığın boşalır. Çıktı: 4 2 3 9 — her düğüm bir kez, en fazla h + 2 = 4 çerçeve.

public void kokSonda(AgacDugumu kok) {
  if (kok == null) {
    return;
  }
  kokSonda(kok.sol);
  kokSonda(kok.sag);
  System.out.print(kok.veri + " ");
}

Gezinmeler · Kodu adım adım çalıştır

Yığın ile Kök Başta Gezinme

1234567Yığın1üstşimdiyığındayazdırıldı

Kök yığına itilir. Yığın, özyinelemedeki çağrı yığınının yerini tutar.

1234567Yığınboşşimdiyığındayazdırıldı

pop() üstteki 1'i verir; hemen yazdırılır (kök başta: önce kök).

1234567Yığın3üstşimdiyığındayazdırıldı

Sağ çocuk 3 itilir. Önce sağ itilir ki sol üstte kalıp önce işlensin (LIFO).

1234567Yığın32üstşimdiyığındayazdırıldı

Sol çocuk 2 itilir → yığının üstünde; bir sonraki pop() onu verir.

1234567Yığın3üstşimdiyığındayazdırıldı

pop() üstteki 2'yi verir; hemen yazdırılır (kök başta: önce kök).

1234567Yığın35üstşimdiyığındayazdırıldı

Sağ çocuk 5 itilir. Önce sağ itilir ki sol üstte kalıp önce işlensin (LIFO).

1234567Yığın354üstşimdiyığındayazdırıldı

Sol çocuk 4 itilir → yığının üstünde; bir sonraki pop() onu verir.

1234567Yığın35üstşimdiyığındayazdırıldı

pop() üstteki 4'ü verir; hemen yazdırılır (kök başta: önce kök). 4 yaprak: itilecek çocuk yok.

1234567Yığın3üstşimdiyığındayazdırıldı

pop() üstteki 5'i verir; hemen yazdırılır (kök başta: önce kök). 5 yaprak: itilecek çocuk yok.

1234567Yığınboşşimdiyığındayazdırıldı

pop() üstteki 3'ü verir; hemen yazdırılır (kök başta: önce kök).

1234567Yığın7üstşimdiyığındayazdırıldı

Sağ çocuk 7 itilir. Önce sağ itilir ki sol üstte kalıp önce işlensin (LIFO).

1234567Yığın76üstşimdiyığındayazdırıldı

Sol çocuk 6 itilir → yığının üstünde; bir sonraki pop() onu verir.

1234567Yığın7üstşimdiyığındayazdırıldı

pop() üstteki 6'yı verir; hemen yazdırılır (kök başta: önce kök). 6 yaprak: itilecek çocuk yok.

1234567Yığınboşşimdiyığındayazdırıldı

pop() üstteki 7'yi verir; hemen yazdırılır (kök başta: önce kök). 7 yaprak: itilecek çocuk yok.

1234567Yığınboşşimdiyığındayazdırıldı

Yığın boş → döngü biter. Çıktı: 1 2 4 5 3 6 7 — özyinelemeli kök başta ile aynı.

public void kokBastaYigin(AgacDugumu kok) {
  if (kok == null) return;
  Deque<AgacDugumu> yigin = new ArrayDeque<>();
  yigin.push(kok);
  while (!yigin.isEmpty()) {
    AgacDugumu gecici = yigin.pop();
    System.out.print(gecici.veri + " ");
    if (gecici.sag != null)
      yigin.push(gecici.sag);  // önce sağ
    if (gecici.sol != null)
      yigin.push(gecici.sol);  // sol üstte
  }
}

Gezinmeler · Kodu adım adım çalıştır

Yığın ile Kök Ortada Gezinme

123456Yığınboşşimdiyığındayazdırıldı

gecici kökten başlar; yığın boş.

123456Yığın1üstşimdiyığındayazdırıldı

1 itilir (sonra yazdırılacak), gecici = 1.sol = 2. Sola inmeye devam.

123456Yığın12üstşimdiyığındayazdırıldı

2 itilir (sonra yazdırılacak), gecici = 2.sol = 4. Sola inmeye devam.

123456Yığın124üstşimdiyığındayazdırıldı

4 itilir (sonra yazdırılacak), gecici = 4.sol = null. Sola gidilecek yer kalmadı.

123456Yığın12üstşimdiyığındayazdırıldı

gecici null → 4 çıkarılıp yazdırılır (solundakilerin hepsi bitti). gecici = 4.sag = null.

123456Yığın1üstşimdiyığındayazdırıldı

gecici null → 2 çıkarılıp yazdırılır (solundakilerin hepsi bitti). gecici = 2.sag = 5.

123456Yığın15üstşimdiyığındayazdırıldı

5 itilir (sonra yazdırılacak), gecici = 5.sol = null. Sola gidilecek yer kalmadı.

123456Yığın1üstşimdiyığındayazdırıldı

gecici null → 5 çıkarılıp yazdırılır (solundakilerin hepsi bitti). gecici = 5.sag = null.

123456Yığınboşşimdiyığındayazdırıldı

gecici null → 1 çıkarılıp yazdırılır (solundakilerin hepsi bitti). gecici = 1.sag = 3.

123456Yığın3üstşimdiyığındayazdırıldı

3 itilir (sonra yazdırılacak), gecici = 3.sol = 6. Sola inmeye devam.

123456Yığın36üstşimdiyığındayazdırıldı

6 itilir (sonra yazdırılacak), gecici = 6.sol = null. Sola gidilecek yer kalmadı.

123456Yığın3üstşimdiyığındayazdırıldı

gecici null → 6 çıkarılıp yazdırılır (solundakilerin hepsi bitti). gecici = 6.sag = null.

123456Yığınboşşimdiyığındayazdırıldı

gecici null → 3 çıkarılıp yazdırılır (solundakilerin hepsi bitti). gecici = 3.sag = null.

123456Yığınboşşimdiyığındayazdırıldı

Yığın boş ve gecici null → döngü biter. Çıktı: 4 2 5 1 6 3 (sol → kök → sağ).

public void kokOrtadaYigin(AgacDugumu kok) {
  if (kok == null) return;
  Deque<AgacDugumu> yigin = new ArrayDeque<>();
  AgacDugumu gecici = kok;
  while (!yigin.isEmpty() || gecici != null) {
    if (gecici != null) {
      yigin.push(gecici);
      gecici = gecici.sol;
    } else {
      gecici = yigin.pop();
      System.out.print(gecici.veri + " ");
      gecici = gecici.sag;
    }
  }
}

Gezinmeler

Yığın ile Kök Sonda Gezinme: Kod

public void kokSondaYigin(AgacDugumu kok) {
  AgacDugumu simdiki = kok;
  Deque<AgacDugumu> yigin = new ArrayDeque<>();
  while (simdiki != null || !yigin.isEmpty()) {
    if (simdiki != null) {
      yigin.push(simdiki);
      simdiki = simdiki.sol;
    } else {
      AgacDugumu gecici = yigin.peek().sag;
      if (gecici == null) {
        gecici = yigin.pop();
        System.out.print(gecici.veri + " ");
        while (!yigin.isEmpty()
           && gecici == yigin.peek().sag) {
          gecici = yigin.pop();
          System.out.print(gecici.veri + " ");
        }
      } else {
        simdiki = gecici;
      }
    }
  }
}
  • Kök, iki alt ağacı da bittikten sonra yazdırılmalı; bu yüzden yığındaki düğüm hemen çıkarılmaz, önce peek ile bakılır.
  • Üstteki düğümün sağ çocuğu varsa önce o alt ağaca gidilir.
  • Sağ çocuk yoksa düğüm yazdırılır. Az önce yazdırılan düğüm, yığındakinin sağ çocuğuysa o ebeveynin de işi bitmiştir → o da çıkarılıp yazdırılır.

Gezinmeler · Kodu adım adım çalıştır

Yığın ile Kök Sonda Gezinme: İzleme

123456Yığınboşşimdiyığındayazdırıldı

simdiki kökten başlar, yığın boş.

123456Yığın1üstşimdiyığındayazdırıldı

1 itilir, simdiki = 1.sol = 2.

123456Yığın12üstşimdiyığındayazdırıldı

2 itilir, simdiki = 2.sol = 4.

123456Yığın124üstşimdiyığındayazdırıldı

4 itilir, simdiki = 4.sol = null.

123456Yığın12üstşimdiyığındayazdırıldı

peek() = 4, sağ çocuğu yok → iki alt ağacı da bitmiş sayılır: 4 çıkarılıp yazdırılır.

123456Yığın12üstşimdiyığındayazdırıldı

4, üstteki 2'nin sağ çocuğu değil (2.sag = 5) → iç döngü durur; 2'nin sağ alt ağacına henüz girilmedi.

123456Yığın12üstşimdiyığındayazdırıldı

peek() = 2; sağ çocuğu 5 var → 2 henüz yazdırılamaz, önce simdiki = 5 ile sağ alt ağaca gidilir.

123456Yığın125üstşimdiyığındayazdırıldı

5 itilir, simdiki = 5.sol = null.

123456Yığın12üstşimdiyığındayazdırıldı

peek() = 5, sağ çocuğu yok → iki alt ağacı da bitmiş sayılır: 5 çıkarılıp yazdırılır.

123456Yığın1üstşimdiyığındayazdırıldı

Az önce yazdırılan düğüm, 2'nin sağ çocuğuydu → 2'nin sağ alt ağacı da bitti: 2 çıkarılıp yazdırılır.

123456Yığın1üstşimdiyığındayazdırıldı

2, üstteki 1'in sağ çocuğu değil (1.sag = 3) → iç döngü durur; 1'in sağ alt ağacına henüz girilmedi.

123456Yığın1üstşimdiyığındayazdırıldı

peek() = 1; sağ çocuğu 3 var → 1 henüz yazdırılamaz, önce simdiki = 3 ile sağ alt ağaca gidilir.

123456Yığın13üstşimdiyığındayazdırıldı

3 itilir, simdiki = 3.sol = null.

123456Yığın13üstşimdiyığındayazdırıldı

peek() = 3; sağ çocuğu 6 var → 3 henüz yazdırılamaz, önce simdiki = 6 ile sağ alt ağaca gidilir.

123456Yığın136üstşimdiyığındayazdırıldı

6 itilir, simdiki = 6.sol = null.

123456Yığın13üstşimdiyığındayazdırıldı

peek() = 6, sağ çocuğu yok → iki alt ağacı da bitmiş sayılır: 6 çıkarılıp yazdırılır.

123456Yığın1üstşimdiyığındayazdırıldı

Az önce yazdırılan düğüm, 3'ün sağ çocuğuydu → 3'ün sağ alt ağacı da bitti: 3 çıkarılıp yazdırılır.

123456Yığınboşşimdiyığındayazdırıldı

Az önce yazdırılan düğüm, 1'in sağ çocuğuydu → 1'in sağ alt ağacı da bitti: 1 çıkarılıp yazdırılır.

123456Yığınboşşimdiyığındayazdırıldı

Yığın boşaldı → iç döngü durur.

123456Yığınboşşimdiyığındayazdırıldı

simdiki null ve yığın boş → biter. Çıktı: 4 5 2 6 3 1 (sol → sağ → kök).

public void kokSondaYigin(AgacDugumu kok) {
  AgacDugumu simdiki = kok;
  Deque<AgacDugumu> yigin = new ArrayDeque<>();
  while (simdiki != null || !yigin.isEmpty()) {
    if (simdiki != null) {
      yigin.push(simdiki);
      simdiki = simdiki.sol;
    } else {
      AgacDugumu gecici = yigin.peek().sag;
      if (gecici == null) {
        gecici = yigin.pop();
        System.out.print(gecici.veri + " ");
        while (!yigin.isEmpty()
           && gecici == yigin.peek().sag) {
          gecici = yigin.pop();
          System.out.print(gecici.veri + " ");
        }
      } else {
        simdiki = gecici;
      }
    }
  }
}

Gezinmeler · Kodu adım adım çalıştır

Kuyruk ile Seviye Sırası Gezinme

43758Kuyruk4önşimdikuyruktayazdırıldı

Kök kuyruğa eklenir. Kuyruk FIFO: önce eklenen önce çıkar.

43758Kuyrukboşşimdikuyruktayazdırıldı

poll() öndeki 4'ü verir ve 4 yazdırılır.

43758Kuyruk3önşimdikuyruktayazdırıldı

Sol çocuk 3 kuyruğun arkasına eklenir; kendi seviyesindekilerden sonra işlenecek.

43758Kuyruk37önarkaşimdikuyruktayazdırıldı

Sağ çocuk 7 arkaya eklenir.

43758Kuyruk7önşimdikuyruktayazdırıldı

poll() öndeki 3'ü verir ve 3 yazdırılır.

43758Kuyruk75önarkaşimdikuyruktayazdırıldı

Sol çocuk 5 kuyruğun arkasına eklenir; kendi seviyesindekilerden sonra işlenecek.

43758Kuyruk758önarkaşimdikuyruktayazdırıldı

Sağ çocuk 8 arkaya eklenir.

43758Kuyruk58önarkaşimdikuyruktayazdırıldı

poll() öndeki 7'yi verir ve 7 yazdırılır. Yaprak: eklenecek çocuk yok.

43758Kuyruk8önşimdikuyruktayazdırıldı

poll() öndeki 5'i verir ve 5 yazdırılır. Yaprak: eklenecek çocuk yok.

43758Kuyrukboşşimdikuyruktayazdırıldı

poll() öndeki 8'i verir ve 8 yazdırılır. Yaprak: eklenecek çocuk yok.

43758Kuyrukboşşimdikuyruktayazdırıldı

Kuyruk boş → döngü biter. Çıktı: 4 3 7 5 8 — seviye seviye (kök başta olsaydı: 4 3 5 8 7).

public void seviyeSirasi(AgacDugumu kok) {
  if (kok == null) return;
  Queue<AgacDugumu> kuyruk = new LinkedList<>();
  kuyruk.add(kok);
  while (!kuyruk.isEmpty()) {
    AgacDugumu gecici = kuyruk.poll();
    System.out.print(gecici.veri + " ");
    if (gecici.sol != null)
      kuyruk.add(gecici.sol);
    if (gecici.sag != null)
      kuyruk.add(gecici.sag);
  }
}

Gezinmeler

Uygulama: İfade Ağacı

  • İç düğümler işleçler, yapraklar işlenenlerdir.
  • Aynı ağaç, gezinme türüne göre farklı gösterimler verir.
  • Değer, kök sonda gezinmeyle hesaplanır: önce iki alt ağacın değeri, sonra işleç.
×+−3452
GezinmeÇıktıGösterim
Kök başta× + 3 4 − 5 2önek (prefix)
Kök ortada3 + 4 × 5 − 2 → parantezle: (3 + 4) × (5 − 2)ara ek (infix)
Kök sonda3 4 + 5 2 − × → 7 × 3 = 21sonek (postfix)

Kök ortada çıktısında parantez kaybolur; ifadeyi doğru yazmak için her alt ağaç parantez içine alınmalıdır.

Gezinmeler · Kodu adım adım çalıştır

İfade Ağacını Hesaplama: hesapla()

×+−3452

hesapla(×): iç düğüm (işleç). İşleci uygulamadan önce sol işlenenin değeri gerekir → hesapla(+).

×+−3452

hesapla(+): iç düğüm (işleç). İşleci uygulamadan önce sol işlenenin değeri gerekir → hesapla(3).

×+−3452↑ 3

hesapla(3): çocuğu yok → yaprak, sayıyı döndürür: 3.

×+−3452↑ 3

a = 3 geldi. Şimdi sağ işlenen: hesapla(4).

×+−3452↑ 3↑ 4

hesapla(4): çocuğu yok → yaprak, sayıyı döndürür: 4.

×+−3452↑ 3↑ 4↑ 7

b = 4. İki alt ağaç hazır → işleç uygulanır: 3 + 4 = 7 döner (kök sonda mantığı).

×+−3452↑ 3↑ 4↑ 7

a = 7 geldi. Şimdi sağ işlenen: hesapla(−).

×+−3452↑ 3↑ 4↑ 7

hesapla(−): iç düğüm (işleç). İşleci uygulamadan önce sol işlenenin değeri gerekir → hesapla(5).

×+−3452↑ 3↑ 4↑ 7↑ 5

hesapla(5): çocuğu yok → yaprak, sayıyı döndürür: 5.

×+−3452↑ 3↑ 4↑ 7↑ 5

a = 5 geldi. Şimdi sağ işlenen: hesapla(2).

×+−3452↑ 3↑ 4↑ 7↑ 5↑ 2

hesapla(2): çocuğu yok → yaprak, sayıyı döndürür: 2.

×+−3452↑ 3↑ 4↑ 7↑ 5↑ 2↑ 3

b = 2. İki alt ağaç hazır → işleç uygulanır: 5 − 2 = 3 döner (kök sonda mantığı).

×+−3452↑ 3↑ 4↑ 7↑ 5↑ 2↑ 3↑ 21

b = 3. İki alt ağaç hazır → işleç uygulanır: 7 × 3 = 21 döner (kök sonda mantığı). (3 + 4) × (5 − 2) = 21

int hesapla(IfadeDugumu d) {
  if (d.sol == null && d.sag == null)
    return d.sayi;               // yaprak: işlenen
  int a = hesapla(d.sol);
  int b = hesapla(d.sag);
  switch (d.islec) {             // iç düğüm: işleç
    case '+': return a + b;
    case '-': return a - b;
    case '*': return a * b;
    default:  return a / b;
  }
}

Gezinmeler · Kodu adım adım çalıştır

İkili Ağaçta En Büyük Değeri Bulma

nullnullnullnullnullnull43758

enBuyukBul(4): sonuc = 4; sol alt ağacın en büyüğü sorulur.

nullnullnullnullnullnull43758

enBuyukBul(3): sonuc = 3; sol alt ağacın en büyüğü sorulur.

nullnullnullnullnullnull43758

enBuyukBul(5): sonuc = 5; sol alt ağacın en büyüğü sorulur.

nullMINnullnullnullnullnull43758

enBuyukBul(5.sol): boş alt ağaç → Integer.MIN_VALUE döner; hiçbir değerden büyük olamaz, karşılaştırmayı bozmaz.

nullMINnullnullnullnullnull43758

Sol sonuç MIN geldi (sol = MIN); şimdi sağ alt ağaç.

nullMINnullMINnullnullnullnull43758

enBuyukBul(5.sag): boş alt ağaç → Integer.MIN_VALUE döner; hiçbir değerden büyük olamaz, karşılaştırmayı bozmaz.

nullMINnullMINnullnullnullnull43758↑ 5

Karşılaştırmalar: sol = MIN ≤ 5; sag = MIN ≤ 5. return 5.

nullMINnullMINnullnullnullnull43758↑ 5

Sol sonuç 5 geldi (sol = 5); şimdi sağ alt ağaç.

nullMINnullMINnullnullnullnull43758↑ 5

enBuyukBul(8): sonuc = 8; sol alt ağacın en büyüğü sorulur.

nullMINnullMINnullMINnullnullnull43758↑ 5

enBuyukBul(8.sol): boş alt ağaç → Integer.MIN_VALUE döner; hiçbir değerden büyük olamaz, karşılaştırmayı bozmaz.

nullMINnullMINnullMINnullnullnull43758↑ 5

Sol sonuç MIN geldi (sol = MIN); şimdi sağ alt ağaç.

nullMINnullMINnullMINnullMINnullnull43758↑ 5

enBuyukBul(8.sag): boş alt ağaç → Integer.MIN_VALUE döner; hiçbir değerden büyük olamaz, karşılaştırmayı bozmaz.

nullMINnullMINnullMINnullMINnullnull43758↑ 5↑ 8

Karşılaştırmalar: sol = MIN ≤ 8; sag = MIN ≤ 8. return 8.

nullMINnullMINnullMINnullMINnullnull43758↑ 5↑ 8↑ 8

Karşılaştırmalar: sol = 5 > 3 → sonuc = 5; sag = 8 > 5 → sonuc = 8. return 8.

nullMINnullMINnullMINnullMINnullnull43758↑ 5↑ 8↑ 8

Sol sonuç 8 geldi (sol = 8); şimdi sağ alt ağaç.

nullMINnullMINnullMINnullMINnullnull43758↑ 5↑ 8↑ 8

enBuyukBul(7): sonuc = 7; sol alt ağacın en büyüğü sorulur.

nullMINnullMINnullMINnullMINnullMINnull43758↑ 5↑ 8↑ 8

enBuyukBul(7.sol): boş alt ağaç → Integer.MIN_VALUE döner; hiçbir değerden büyük olamaz, karşılaştırmayı bozmaz.

nullMINnullMINnullMINnullMINnullMINnull43758↑ 5↑ 8↑ 8

Sol sonuç MIN geldi (sol = MIN); şimdi sağ alt ağaç.

nullMINnullMINnullMINnullMINnullMINnullMIN43758↑ 5↑ 8↑ 8

enBuyukBul(7.sag): boş alt ağaç → Integer.MIN_VALUE döner; hiçbir değerden büyük olamaz, karşılaştırmayı bozmaz.

nullMINnullMINnullMINnullMINnullMINnullMIN43758↑ 5↑ 8↑ 8↑ 7

Karşılaştırmalar: sol = MIN ≤ 7; sag = MIN ≤ 7. return 7.

nullMINnullMINnullMINnullMINnullMINnullMIN43758↑ 5↑ 8↑ 8↑ 7↑ 8

Karşılaştırmalar: sol = 8 > 4 → sonuc = 8; sag = 7 ≤ 8. return 8. Sonuç: 8

public int enBuyukBul(AgacDugumu kok) {
  if (kok == null) {
    return Integer.MIN_VALUE;
  }
  int sonuc = kok.veri;
  int sol = enBuyukBul(kok.sol);
  int sag = enBuyukBul(kok.sag);
  if (sol > sonuc)
    sonuc = sol;
  if (sag > sonuc)
    sonuc = sag;
  return sonuc;
}

Gezinmeler

Özyinelemeli Ağaç Fonksiyonları

int boyut(AgacDugumu k) {            // düğüm sayısı
    if (k == null) return 0;
    return 1 + boyut(k.sol) + boyut(k.sag);
}

int yukseklik(AgacDugumu k) {        // kenar sayısı
    if (k == null) return -1;        // boş ağaç: -1
    return 1 + Math.max(yukseklik(k.sol),
                        yukseklik(k.sag));
}

int yaprakSayisi(AgacDugumu k) {
    if (k == null) return 0;
    if (k.sol == null && k.sag == null) return 1;
    return yaprakSayisi(k.sol) + yaprakSayisi(k.sag);
}
Ortak kalıpBoş ağaç için taban durum; aksi halde iki alt ağacın sonucunu birleştir (kök sonda mantığı).
9 → (2 → 4), 3 ağacındaboyut = 4yukseklik = 2yaprakSayisi = 2 (4 ve 3)
MaliyetHer düğüm bir kez işlenir: O(n) zaman, O(h) yığın alanı.

Gezinmeler · Kodu adım adım çalıştır

Kod İzleme: boyut() — değerler yukarı taşınır

nullnullnullnullnull9234şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

boyut(9) (kök): null değil → önce sol alt ağaç için boyut(2) çağrılır.

nullnullnullnullnull9234şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

boyut(2) (9'un sol çocuğu): null değil → önce sol alt ağaç için boyut(4) çağrılır.

nullnullnullnullnull9234şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

boyut(4) (2'nin sol çocuğu): null değil → önce sol alt ağaç için boyut(null) çağrılır.

null0nullnullnullnull9234şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

boyut(4.sol) = boyut(null): boş ağaç → return 0.

null0nullnullnullnull9234şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

Sol sonuç 0 geldi. Şimdi sağ alt ağaç: boyut(null).

null0null0nullnullnull9234şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

boyut(4.sag) = boyut(null): boş ağaç → return 0.

null0null0nullnullnull9234↑ 1şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

boyut(4) = 1 + 0 + 0 = 1 döner. Değer 2'nin çerçevesine taşınır.

null0null0nullnullnull9234↑ 1şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

Sol sonuç 1 geldi. Şimdi sağ alt ağaç: boyut(null).

null0null0null0nullnull9234↑ 1şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

boyut(2.sag) = boyut(null): boş ağaç → return 0.

null0null0null0nullnull9234↑ 1↑ 2şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

boyut(2) = 1 + 1 + 0 = 2 döner. Değer 9'un çerçevesine taşınır.

null0null0null0nullnull9234↑ 1↑ 2şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

Sol sonuç 2 geldi. Şimdi sağ alt ağaç: boyut(3).

null0null0null0nullnull9234↑ 1↑ 2şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

boyut(3) (9'un sağ çocuğu): null değil → önce sol alt ağaç için boyut(null) çağrılır.

null0null0null0null0null9234↑ 1↑ 2şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

boyut(3.sol) = boyut(null): boş ağaç → return 0.

null0null0null0null0null9234↑ 1↑ 2şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

Sol sonuç 0 geldi. Şimdi sağ alt ağaç: boyut(null).

null0null0null0null0null09234↑ 1↑ 2şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

boyut(3.sag) = boyut(null): boş ağaç → return 0.

null0null0null0null0null09234↑ 1↑ 2↑ 1şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

boyut(3) = 1 + 0 + 0 = 1 döner. Değer 9'un çerçevesine taşınır.

null0null0null0null0null09234↑ 1↑ 2↑ 1↑ 4şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

boyut(9) = 1 + 2 + 1 = 4 döner. Sonuç: 4

int boyut(AgacDugumu k) {            // düğüm sayısı
    if (k == null) return 0;
    return 1 + boyut(k.sol) + boyut(k.sag);
}

Gezinmeler · Kodu adım adım çalıştır

Kod İzleme: yukseklik()

nullnullnullnullnull9234şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yukseklik(9) (kök): null değil → önce sol alt ağaç için yukseklik(2) çağrılır.

nullnullnullnullnull9234şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yukseklik(2) (9'un sol çocuğu): null değil → önce sol alt ağaç için yukseklik(4) çağrılır.

nullnullnullnullnull9234şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yukseklik(4) (2'nin sol çocuğu): null değil → önce sol alt ağaç için yukseklik(null) çağrılır.

null-1nullnullnullnull9234şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yukseklik(4.sol) = yukseklik(null): boş ağaç → return -1. Boş ağacın yüksekliği −1 kabul edilir; böylece yaprak 1 + max(−1, −1) = 0 olur.

null-1nullnullnullnull9234şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

Sol sonuç -1 geldi. Şimdi sağ alt ağaç: yukseklik(null).

null-1null-1nullnullnull9234şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yukseklik(4.sag) = yukseklik(null): boş ağaç → return -1.

null-1null-1nullnullnull9234↑ 0şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yukseklik(4) = 1 + max(-1, -1) = 0 döner. Değer 2'nin çerçevesine taşınır.

null-1null-1nullnullnull9234↑ 0şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

Sol sonuç 0 geldi. Şimdi sağ alt ağaç: yukseklik(null).

null-1null-1null-1nullnull9234↑ 0şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yukseklik(2.sag) = yukseklik(null): boş ağaç → return -1.

null-1null-1null-1nullnull9234↑ 0↑ 1şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yukseklik(2) = 1 + max(0, -1) = 1 döner. Değer 9'un çerçevesine taşınır.

null-1null-1null-1nullnull9234↑ 0↑ 1şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

Sol sonuç 1 geldi. Şimdi sağ alt ağaç: yukseklik(3).

null-1null-1null-1nullnull9234↑ 0↑ 1şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yukseklik(3) (9'un sağ çocuğu): null değil → önce sol alt ağaç için yukseklik(null) çağrılır.

null-1null-1null-1null-1null9234↑ 0↑ 1şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yukseklik(3.sol) = yukseklik(null): boş ağaç → return -1.

null-1null-1null-1null-1null9234↑ 0↑ 1şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

Sol sonuç -1 geldi. Şimdi sağ alt ağaç: yukseklik(null).

null-1null-1null-1null-1null-19234↑ 0↑ 1şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yukseklik(3.sag) = yukseklik(null): boş ağaç → return -1.

null-1null-1null-1null-1null-19234↑ 0↑ 1↑ 0şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yukseklik(3) = 1 + max(-1, -1) = 0 döner. Değer 9'un çerçevesine taşınır.

null-1null-1null-1null-1null-19234↑ 0↑ 1↑ 0↑ 2şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yukseklik(9) = 1 + max(1, 0) = 2 döner. Sonuç: 2

int yukseklik(AgacDugumu k) {        // kenar sayısı
    if (k == null) return -1;        // boş ağaç: -1
    return 1 + Math.max(yukseklik(k.sol),
                        yukseklik(k.sag));
}

Gezinmeler · Kodu adım adım çalıştır

Kod İzleme: yaprakSayisi()

nullnullnullnullnull9234şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yaprakSayisi(9) (kök): yaprak değil → sol ve sağ alt ağaçların yaprakları toplanacak; önce sol.

nullnullnullnullnull9234şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yaprakSayisi(2) (9'un sol çocuğu): yaprak değil → sol ve sağ alt ağaçların yaprakları toplanacak; önce sol.

nullnullnullnullnull9234↑ 1şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yaprakSayisi(4) (2'nin sol çocuğu): iki çocuğu da null → yaprak, return 1. Alt çağrı yapılmaz.

nullnullnull0nullnull9234↑ 1şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yaprakSayisi(2.sag) = yaprakSayisi(null): boş ağaç → return 0.

nullnullnull0nullnull9234↑ 1↑ 1şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yaprakSayisi(2) = 1 + 0 = 1 döner.

nullnullnull0nullnull9234↑ 1↑ 1↑ 1şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yaprakSayisi(3) (9'un sağ çocuğu): iki çocuğu da null → yaprak, return 1. Alt çağrı yapılmaz.

nullnullnull0nullnull9234↑ 1↑ 1↑ 1↑ 2şimdi çalışanyığında, bekliyordeğerini döndürdühenüz çağrılmadı

yaprakSayisi(9) = 1 + 1 = 2 döner. Sonuç: 2

int yaprakSayisi(AgacDugumu k) {
    if (k == null) return 0;
    if (k.sol == null && k.sag == null) return 1;
    return yaprakSayisi(k.sol) + yaprakSayisi(k.sag);
}

Gezinmeler · Kodu adım adım çalıştır

Kod İzleme: kök başta + kök ortada'dan ağacı kurma

pre102142533465pin402152133465[0..5]1

pre[0] = 1 → yeni düğüm (kök). in'de m = 3: [0..2] sol alt ağaç, [4..5] sağ alt ağaç olur.

pre102142533465pin402152133465[0..2]12

pre[1] = 2 → yeni düğüm (1'in sol çocuğu). in'de m = 1: [0..0] sol alt ağaç, [2..2] sağ alt ağaç olur.

pre102142533465pin402152133465[0..0]124

pre[2] = 4 → yeni düğüm (2'nin sol çocuğu); m = 0. Sol ve sağ aralık boş → iki çağrı null döner: 4 yaprak.

pre102142533465pin402152133465[2..2]1245

pre[3] = 5 → yeni düğüm (2'nin sağ çocuğu); m = 2. Sol ve sağ aralık boş → iki çağrı null döner: 5 yaprak.

pre102142533465pin402152133465[0..2]1245

2'nin alt ağaçları kuruldu → return düğüm(2); 1.sol = 2 yapılır.

pre102142533465pin402152133465[4..5]12453

pre[4] = 3 → yeni düğüm (1'in sağ çocuğu). in'de m = 4: [4..3] sol alt ağaç, [5..5] sağ alt ağaç olur.

pre102142533465pin402152133465boş: 4 > 312453

Sol aralık [4..3] boş → kur hemen null döner: 3'ün sol çocuğu yok.

pre102142533465pin402152133465[5..5]124536

pre[5] = 6 → yeni düğüm (3'ün sağ çocuğu); m = 5. Sol ve sağ aralık boş → iki çağrı null döner: 6 yaprak.

pre102142533465pin402152133465[4..5]124536

3'ün alt ağaçları kuruldu → return düğüm(3); 1.sag = 3 yapılır.

pre102142533465pin402152133465[0..5]124536

1'in alt ağaçları kuruldu → return düğüm(1); kök olarak kok'a atanır. Sonuç: 1(2(4, 5), 3(—, 6)). m araması yüzünden O(n2); in[] indisleri bir eşlemede (map) tutulursa O(n).

int p = 0; // pre[] içinde sıradaki kök
AgacDugumu kur(int[] pre, int[] in, int bas, int son) {
    if (bas > son) return null;       // boş aralık
    AgacDugumu k = new AgacDugumu(pre[p++]);
    int m = bas; while (in[m] != k.veri) m++;
    k.sol = kur(pre, in, bas, m - 1); // soldakiler
    k.sag = kur(pre, in, m + 1, son); // sağdakiler
    return k;
}

Gezinmeler

Gezinmelerin Maliyeti

YöntemZamanEk bellekNeden?
Özyinelemeli pre/in/postO(n)O(h)Çağrı yığınında en fazla h + 2 çerçeve (null çağrısı dahil)
Yığın ile pre/in/postO(n)O(h)Açık yığın, özyinelemenin yerini tutar
Kuyruk ile seviye sırasıO(n)O(w)w: en geniş seviyedeki düğüm sayısı
h ne kadar?Dengeli ağaçta h ≈ log2 n; çarpık ağaçta h = n − 1. Çok derin ağaçlarda özyineleme StackOverflowError verebilir → yığınlı sürüm tercih edilir.
w ne kadar?Mükemmel ağaçta son seviyede ≈ n/2 düğüm vardır; seviye sırası geniş ağaçlarda daha çok bellek harcar.

Özet

Özet

KonuHatırlanacaklar
Terimlerkök, ebeveyn/çocuk, yaprak, iç düğüm; n düğüm → n − 1 kenar
Ölçülerderece = çocuk sayısı; derinlik = kökten kenar sayısı; yükseklik = en uzun aşağı yol
İkili ağaçdolu: 0/2 çocuk · tam: son seviye soldan dolar · mükemmel: tüm seviyeler dolu
Gösterimdizi: indis bağıntıları · bağlı: sol/sağ referansları
Gezinmekök başta K-S-S · kök ortada S-K-S · kök sonda S-S-K · seviye sırası kuyrukla
Maliyettüm gezinmeler O(n); ek bellek O(h) (yığın) veya O(w) (kuyruk)

Özet

Etkileşimli Simülatörler

Genel AğaçÇocuk sayısı sınırsız ağaçta düğüm ekleme/silme ve gezinmeler.
İkili (Arama) Ağaçİkili ağaç üzerinde ekleme ve kök başta / ortada / sonda gezinmeleri izleme.

Özet

Sık Yapılan Hatalar

Taban durumu unutmakk.sol'a erişmeden önce k == null denetlenmezse NullPointerException. Her özyinelemeli ağaç metodu boş ağaçla başlar.
Yükseklik tanımını karıştırmakKenar sayısıyla: yaprak 0, boş ağaç −1. Düğüm sayısıyla: yaprak 1, boş ağaç 0. Bir tanım seçip tutarlı kullanın.
Dolu ≠ tamDolu: her düğümde 0 ya da 2 çocuk. Tam: son seviye hariç dolu, son seviye soldan. Biri diğerini gerektirmez.
Tek gezinmeden ağaç kurmakTek bir sıra ağacı belirlemez. Kök ortada + (kök başta ya da kök sonda) gerekir; kök başta + kök sonda tek çocuklu düğümlerde belirsizdir.
İndis formülünü karıştırmak1 tabanlı: 2i, 2i + 1, ⌊i/2⌋. 0 tabanlı: 2i + 1, 2i + 2, ⌊(i − 1)/2⌋.
Derin ağaçta özyinelemeÇarpık ağaçta h = n − 1: yüz binlerce çerçeve StackOverflowError verir → yığınlı ya da kuyruklu sürüm.

Özet

Örnek Problemler

  1. Sağdaki ağacın kök başta, kök ortada, kök sonda ve seviye sırası çıktılarını yazın.
  2. Ağacın yüksekliği nedir? Yapraklar hangileri? E'nin derinliği kaçtır?
  3. Bu ağaç dolu mu, tam mı, mükemmel mi?
  4. 1 tabanlı dizi gösteriminde F ve G hangi indislerde durur? Dizi en az kaç hücre olmalı?
  5. Yüksekliği 4 olan bir ikili ağaçta en fazla kaç düğüm olabilir?
  6. Kök başta: A B D E C F, kök ortada: D B E A C F. Ağacı çizin.
ABCDEFG
Cevapları göster
  1. Kök başta: A B D E G C F · kök ortada: D B G E A C F · kök sonda: D G E B F C A · seviye: A B C D E F G
  2. Yükseklik 3 (A→B→E→G); yapraklar D, G, F; E'nin derinliği 2.
  3. Hiçbiri: E ve C'nin tek çocuğu var (dolu değil); 6. konum boşken 7 dolu (tam değil).
  4. F: C'nin sağ çocuğu → 2·3 + 1 = 7; G: E'nin sol çocuğu → 2·5 = 10. En az 10 hücre (1..10).
  5. 25 − 1 = 31.
  6. A kök; sol alt ağaç {D, B, E}: B kök, D sol, E sağ; sağ alt ağaç {C, F}: C kök, F sağ çocuk.

Özet

Alıştırmalar

  1. int icDugumSayisi(AgacDugumu k): iç düğümleri sayan metodu yazın.
  2. void ayna(AgacDugumu k): ağacın aynadaki görüntüsünü (her düğümde sol ↔ sağ) oluşturun.
  3. boolean esitMi(AgacDugumu a, AgacDugumu b): iki ağaç şekil ve değerce aynı mı?
  4. int seviyedeki(AgacDugumu k, int d): d derinliğindeki düğüm sayısını bulun.
  5. Kök sonda: D E B F C A, kök ortada: D B E A F C. Ağacı çizin.
  6. n düğümlü dolu ikili ağaçta kaç yaprak vardır? n çift olabilir mi?
Cevaplar / ipuçları
  1. null ya da yaprak → 0; değilse 1 + sol + sağ. O(n).
  2. Kök sonda: ayna(k.sol); ayna(k.sag); sonra k.sol ile k.sag'ı takas et.
  3. İkisi de null → true; biri null → false; değilse veri eşit && sollar eşit && sağlar eşit.
  4. d == 0 → 1; değilse seviyedeki(k.sol, d−1) + seviyedeki(k.sag, d−1); null → 0.
  5. Kök A (son); sol {D, B, E}: B(D, E); sağ {F, C}: C, F sol çocuk → A(B(D, E), C(F, —)).
  6. y = i + 1 ve n = i + y → y = (n + 1)/2; n = 2i + 1 hep tektir.

Özet

Kaynaklar

  • Goodrich, Tamassia ve Goldwasser, Data Structures and Algorithms in Java, 6. baskı, 2014.
  • Cormen, Leiserson, Rivest ve Stein, Introduction to Algorithms, 4. baskı, 2022.
  • Sedgewick ve Wayne, Algorithms, 4. baskı, 2011.

Son

Bölüm 9: Ağaçlar
Sonraki sunum: Bölüm 10: Arama Ağaçları · Çalışma soruları · Simülatörler: General Tree Simulator, Binary Search Tree Simulator · Terim sözlüğü
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.