11  İkili Ağaçlar — Bölüm 2: AVL

Dizi ağaçları (subtree_at, size), alt ağaç zenginleştirme (O(1) güncelleme kuralı), rotasyon (traversal sırası korunur), AVL skew ∈ {−1, 0, +1} ve Nₕ Fibonacci-benzeri üstel büyüme → h ≤ 2 log n garantisi

NotBölüm bilgisi

11.1 Bu Derste Ne Var?

Ders 9 (L6) ikili ağaçları kurdu: tüm işlemler \(O(h)\) (\(h\) = yükseklik). Açık kalan tek soru vardı — \(h\)’yi nasıl küçük tutarız? Bu ders onu kapatır: AVL ağaçları ve rotasyon ile \(h = O(\log n)\) garanti edilir, böylece tüm \(O(h)\) işlemler \(O(\log n)\) olur.

Üç temel kavram bu derste yan yana gelir:

  1. Dizi ağaçları + alt ağaç zenginleştirmesize alanıyla \(i\). öğeye \(O(h)\)’de erişim (subtree_at).
  2. Rotasyon — traversal sırasını bozmadan ağacı yeniden dengeleyen araç.
  3. AVL / yükseklik dengesi — her düğümde skew \(\in \{-1, 0, +1\}\); bu, \(h \le 2 \log n\)’i garanti eder.

“the goal of today is to take all of these operations that run in order h time and get them to run in order log n time.” — Demaine, 3:05

flowchart TD
    A["Ders 10 (L7): İkili Ağaçlar — Bölüm 2: AVL"] --> G["Hedef: O(h) işlemleri<br/>O(log n)'e indir"]
    G --> SA["subtree_at<br/>i. öğeye boyut-temelli arama"]
    SA --> SZ["size alanı<br/>her düğümde alt ağaç boyutu"]
    SZ --> AU["Augmentation kuralı<br/>size = sol + sağ + 1 (O(1))"]
    G --> RO["Rotasyon<br/>sıra korunur (A, X, B, Y, C)"]
    RO --> RO1["derinlikler değişir<br/>yeniden dengeleme aracı"]
    AU --> AV["AVL kuralı<br/>skew −1, 0 veya +1"]
    RO --> AV
    AV --> HB["En az dengeli AVL: Nₕ Fibonacci-benzeri<br/>üstel düğüm sayısı"]
    HB --> RES["h en çok 2 log n<br/>tüm işlemler O(log n)"]

    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
    classDef goal fill:#fde68a,stroke:#b45309,stroke-width:2.5px,color:#1f2937
    class A root
    class SA,RO,AV,HB branch
    class SZ,AU,RO1,RES leaf
    class G,RES goal
Şekil 11.1: Ders 10’un (L7) kavram haritası: hedef, dünkü O(h) işlemleri O(log n)’e indirmek. İki köprü ekleniyor — (1) dizi ağacında subtree_at, her düğümdeki size alanıyla boyut-temelli ikili arama yapar; size ise alt ağaç zenginleştirme kuralından (node.size = sol + sağ + 1, O(1) güncelleme) gelir. (2) rotasyon, traversal sırasını (A, X, B, Y, C) ASLA bozmadan derinlikleri değiştirir → yeniden dengeleme aracı. AVL kuralı bunu skew ∈ {−1, 0, +1} ile sabitler; en az dengeli AVL’nin düğüm sayısı Nₕ Fibonacci-benzeri (üstel) olduğundan yükseklik h ≤ 2 log n çıkar. Sonuç: her sequence/set işlemi O(log n).
İpucuBuilder Notu — Denge = Garanti Mühendisliği

İkili ağaç tek başına \(O(h)\)’dir; bugün yapılan tek şey, o \(h\)’ye bir üst sınır garantisi eklemek — yapıyı yeniden kurmadan, sadece dengeleyerek.

  • Geriye → Ders 3 (ikili arama): BST’deki find, sıralı dizideki ikili aramanın ağaç hâlidir — ama artık dinamik (insert/delete \(O(\log n)\)).
  • Geriye → Ders 9 (L6): bugün, dünkü \(O(h)\) işlemlerin üstüne yalnızca denge ekliyoruz; alt yapı (düğüm, traversal, successor) aynı.
  • İleriye → veritabanı: B-tree / B+-tree, dengeli ağacın disk-dostu hâlidir; çoğu SQL indeksi ve dosya sistemi dizini bu fikre dayanır (varsayılan indeks tipik olarak bir dengeli ağaçtır).
  • İleriye → order-statistics tree: size zenginleştirmesi, “rank” ve “\(k\). en küçük” sorgularını \(O(\log n)\)’de yapar — sıralama istatistikleri.

Tek cümle: İkili ağaca size/height gibi alt ağaç özellikleri ekleyip rotasyonla yükseklik dengesi (AVL) tutarsak, her işlem \(O(\log n)\) olur — dengeli ağacın tüm gücü budur.

11.2 Geçen Dersten: O(h) İşlemler ve Bugünkü Hedef

Ders 9’da (L6) ikili ağaç düğümü item + node.left/node.right/node.parent tutuyordu; yükseklik (en uzun aşağı yoldaki kenar sayısı) tanımlandı; traversal sırası (sol → kök → sağ) örtük düzeni kodluyordu. subtree_first/last, predecessor/successor, insert/delete — hepsi \(O(h)\).

Sorun: en kötü durumda \(h\) lineerdir (yalnız sağ işaretçiler kullanılan zincir ağaç). Bugün \(h = O(\log n)\) garanti edip tüm işlemleri \(O(\log n)\)’e indireceğiz — veri yapısını yeniden kurmadan, sadece dengeleyerek.

11.3 Küme Ağaçları = İkili Arama Ağaçları (BST)

Küme için traversal sırasını artan anahtar yaparsak, subtree_find bir ikili arama olur: kökten başla, aranan anahtar düğümünkinden küçükse node.left’e, büyükse node.right’e in, eşitse bulundu.

“set binary trees are called binary search trees, because they’re the tree version of binary search.” — Demaine, 6:30

Bunu doğru kılan BST özelliği: bir düğümün sol alt ağacındaki tüm anahtarlar \(<\) düğüm \(<\) sağ alt ağacındaki tüm anahtarlar (özyinelemeli). Bu, traversal sırası tanımının (sol önce, sağ sonra) doğrudan sonucudur. find_prev/find_next: ağaçtan düşersen, son denenen yön sana komşuyu verir. \(O(h)\).

11.4 Dizi Ağaçları: subtree_at

Dizi için traversal sırasını sequence sırası yaparız; ama “\(i\). öğeyi getir” (subtree_at) için artık anahtar yok — sıra numarasıyla aramamız gerekir. Anahtar fikir: her düğümde alt ağaç boyutu size’ı bil.

Çalışılan Örnek — subtree_at. \(n_\ell\) = node.left.size (sol alt ağaçtaki düğüm sayısı) olsun. \(i\). öğeyi ararken:

  • \(i < n_\ell\) → öğe sol alt ağaçta → subtree_at(node.left, i).
  • \(i = n_\ell\) → kökün indeksi tam \(n_\ell\)’dir → node’u döndür.
  • \(i > n_\ell\) → öğe sağ alt ağaçta → subtree_at(node.right, i − nₗ − 1) (sol için \(n_\ell\), kök için 1 çıkar).

Bu, BST find’in anahtar yerine boyut kullanan ikizidir; \(O(h)\). Bununla get_at/set_at (düğümü bul, item’ı oku/değiştir) ve — ilk kez! — insert_at/delete_at (\(i\)’yi bul, subtree_insert_before ile araya ekle) yapılır; tüm indeksler kendiliğinden güncellenir, çünkü indeks saklanmıyor.

Şekil 11.2 bunu somut bir örnekte gösterir: build_avl(range(15)) mükemmel dengeli ağacında (kök \(7\), \(h = 3\)) \(i = 10\) aranır; yol \(7 \to 11 \to 9 \to 10\) ile öğe bulunur.

Şekil 11.2: subtree_at — size ile boyut-temelli ikili arama, O(h) (L7 §3). Deterministik örnek build_avl(range(15)): kök 7, h = 3, size = 15. Aranan i = 10. Her yol düğümünün üstünde karar kutusu (motordan): 7 (nₗ = 7, i = 10) → i > nₗ → SAĞ, i ← 10 − 7 − 1 = 2; 11 (nₗ = 3, i = 2) → i < nₗ → SOL; 9 (nₗ = 1, i = 2) → i > nₗ → SAĞ, i ← 2 − 1 − 1 = 0; 10 (nₗ = 0, i = 0) → i = nₗ → BULUNDU (amber dolgu). Her düğümün yanında küçük slate size rozeti (s = N). BST find anahtar yerine BOYUT kullanır: nₗ = node.left.size. Her adım bir seviye iner → yol uzunluğu ≤ h = 3 → O(h).

11.5 Alt Ağaç Zenginleştirme (Subtree Augmentation)

Peki size’ı nasıl \(O(1)\)’de biliriz? Alt ağaç zenginleştirmesiyle: her düğüm sabit sayıda ekstra alan tutar. Bir alt ağaç özelliği (subtree property), düğümün çocuklarının özelliklerinden \(O(1)\)’de hesaplanabilen, “aşağı bakan” bir niceliktir.

“I’m going to define a subtree property to be something that can be computed from the properties of the node’s children.” — Demaine, 16:10

size tam da böyledir:

\[\texttt{node.size} = \texttt{node.left.size} + \texttt{node.right.size} + 1\]

“node.size equals node.left.size plus node.right.size plus 1.” — Demaine, 17:43

Bu bir güncelleme kuralıdır (\(O(1)\)). size saklanır, özyinelemeli yeniden hesaplanmaz (return node.size\(O(1)\)). Insert/delete sonunda bir yaprak ekler/siler; yalnızca o yaprağın ataları (ancestors) değişir → ata yolunu yukarı çıkıp her birinde güncelleme kuralını uygula, \(O(h)\). Bu, tümevarımla doğrudur: alt çocuklar zaten güncelse, kural ile düğüm \(O(1)\)’de güncellenir.

Şekil 11.3 iki panelde bunu gösterir: build_avl(range(7)) (kök \(3\), \(h = 2\)) ağacına \(7\) eklendiğinde yalnız ata yolu \(7 \to 6 \to 5 \to 3\) güncellenir; yolun dışındaki alt ağaçlar dokunulmaz kalır.

Şekil 11.3: Alt ağaç zenginleştirme — yaprak değişimi yalnız ATALARI günceller, O(h) (L7 §4). Sol panel: insert öncesi build_avl(range(7)) (kök 3, h = 2); her düğümün yanında size + height rozeti; altta O(1) güncelleme kuralı kutusu (node.size = sol.size + sağ.size + 1; node.height = 1 + max(sol.height, sağ.height)). Sağ panel: avl_insert(r, 7) sonrası; yeni yaprak 7 amber DOLGU; ata yolu 7 → 6 → 5 → 3 (yapraktan köke) amber KALIN kenar — yalnız bu düğümlerin rozetleri güncellendi. Yolun DIŞINDAki alt ağaçlar soluk + DOKUNULMAZ etiketi. Alt ağaç özelliği AŞAĞI bakar (size/height çocuklardan türer) → yalnız O(h) ata güncellenir (Demaine 16:10).
İpucuBuilder Notu — Order-Statistics: rank ve k. En Küçük

size zenginleştirmesi, dengeli ağacı bir order-statistics tree’ye çevirir: yalnız “\(i\). öğe” değil, ters yönü de — bir öğenin rank’ı (kaçıncı sırada) ve “\(k\). en küçük” sorguları \(O(\log n)\)’de yanıtlanır.

  • rank(x): Kökten \(x\)’e inerken, her sola dönüşte o düğümün \(n_\ell + 1\)’ini (sol alt ağaç + düğüm kendisi) atlamış olursun; toplam atlanan, \(x\)’in sıra numarasıdır. Tam subtree_at’in tersi.
  • \(k\). en küçük: doğrudan subtree_at(kök, k)Şekil 11.2’teki yürüyüşün ta kendisi.
  • Pratik kullanım: “medyanın altında kaç öğe var”, “yüzdelik dilim”, “şu fiyattan ucuz kaç ürün” gibi sorgular; bir sıralı dizide \(O(n)\) olurdu, order-statistics tree’de \(O(\log n)\). (Araya giren Problem Oturumu 4 tam bu tür zenginleştirme problemlerini işler.)

Tek cümle: tek bir size alanı, ağacı hem “\(i\). öğe”yi hem “bu öğe kaçıncı”yı \(O(\log n)\)’de bilen bir sıralama-istatistiği yapısına dönüştürür.

11.6 Hangi Özellikler Tutulabilir?

Alt ağaç özelliği olan her şey: toplam, çarpım, min, max, kare toplamı — alt ağaçtaki düğümlerin herhangi bir alanı üzerinden. (size aslında “her düğüm için 1’in toplamı”dır.)

Ama tutulamayanlar vardır:

  • İndeks (index): global’dir — başa bir düğüm eklersen tüm düğümlerin indeksi değişir. Bir düğümün indeksi, solundaki tüm düğümlere (alt ağaç dışı) bağlıdır.
  • Derinlik (depth): benzer şekilde yukarı-bakan, alt ağaç özelliği değil.

“Index is not a subtree property, and that’s why we can’t maintain it — because it depends on all of the nodes in the tree.” — Demaine, 25:35

Kural: yalnızca aşağı-bakan (alt ağaca özgü) özellikler tutulabilir; global özellikler değil.

İpucuBuilder Notu — Yerel (Kompozisyonel) Olan Tutulur

Bu, veri yapısı tasarımının ötesine geçen bir ilke: bir niceliği verimli güncel tutabilmen, onun yerel (kompozisyonel) olmasına bağlıdır. Yerel = “yalnızca alt parçalardan hesaplanır”; global = “tüm bütüne bağlı”.

  • Aşağı-bakan vs global: size/sum/max çocuklardan \(O(1)\)’de türer → yaprak değişiminde yalnız \(O(h)\) ata güncellenir. index/depth tüm ağaca bağlı → tek ekleme her şeyi kaydırır, \(O(n)\).
  • Dağıtık sistem analojisi: Bir ağaç-toplama (tree aggregation) veya MapReduce’da yalnız birleştirilebilir (associative/composable) agregalar — sum, count, min, max — kısmi sonuçlardan ucuza güncellenir; “global sıra numarası” gibi nicelikler her düğüme tüm veriyi gerektirir.
  • Genel ders: “Bunu \(O(\log n)\)’de tutabilir miyim?” sorusunun cevabı, “bu nicelik çocuklarımdan hesaplanabilir mi?” sorusuyla aynıdır.

Tek cümle: verimli bakım, yerelliğin (kompozisyonelliğin) bir sonucudur — global bir nicelik hiçbir akıllı işaretçi numarasıyla ucuza tutulamaz.

11.7 Ağaç Rotasyonu

Dengeyi sağlamak için yeni bir araç gerekir: rotasyon. Tek işi ağacı yeniden dengelemek; traversal sırasını asla değiştirmemelidir (traversal sırası temsil edilen veridir — dokunulmaz).

“a rotation… a tool for rebalancing the tree. So it should not change the data that’s represented by the tree. … Traversal order is sacrosanct.” — Demaine, 30:07

Çalışılan Örnek — rotasyon. Bir \(y\) düğümü ve sol çocuğu \(x\) düşün; alt ağaçlar \(A\) (\(x\)’in solu), \(B\) (\(x\)’in sağı), \(C\) (\(y\)’nin sağı). right_rotate(y): \(x\) yukarı, \(y\) aşağı geçer; \(B\), \(x\)’ten kopup \(y\)’nin soluna bağlanır. Her iki çizimde de traversal sırası \(A, X, B, Y, C\) kalır (üçgenler özyinelemeli). Yani rotasyon sırayı korur ama derinlikleri değiştirir: \(x\) yukarı (sığlaşır), \(y\) aşağı (derinleşir), bu da yeniden dengeleme imkânı verir. (Simetriği left_rotate(x).) Aynı ağaç düzeni üstel sayıda farklı ağaçla temsil edilebilir; rotasyon bu fazlalığı kullanır.

Şekil 11.4 iki paneli yan yana koyar (öncesi/sonrası); alttaki in-order şerit \(A, X, B, Y, C\) her iki panelde aynen aynı kalır.

Şekil 11.4: right_rotate — yapı değişir, traversal sırası KORUNUR (A, X, B, Y, C) (L7 §6, İMZA figür). Sol panel (öncesi): kök Y, sol çocuğu X; alt ağaçlar A = X.left, B = X.right (amber dolgu = yer değiştirecek), C = Y.right. Kavisli amber ok right_rotate(Y)’yi gösterir. Sağ panel (sonrası): kök X (amber çerçeve); B artık X’in sağından Y’nin SOLUNA taşındı (amber taşıma oku). HER iki panelin altında AYNI in-order şeridi A | X | B | Y | C; ortada SIRA KORUNUR rozeti + eşittir işareti. Rotasyon = O(1) işaretçi takası + augmentation güncelle; in-order dizilim kutsaldır (Demaine 30:07). Motor doğrulaması: right_rotate öncesi avl_to_list = sonrası avl_to_list = [A, X, B, Y, C].
İpucuBuilder Notu — Rotasyon: Tüm Dengeli Ağaçların Ortak İlkeli

Rotasyon, AVL’ye özgü değil — tüm kendini-dengeleyen ağaçların ortak ilkel (primitive) işlemidir. “Sırayı bozmadan derinlik değiştir” mekanizması her yerde aynıdır; ağaçlar yalnızca ne zaman döndüreceklerine dair kuralda ayrışır.

  • red-black tree: Renk kuralları + rotasyon; çoğu standart kütüphane map/set’i (örneğin C++ STL, Java TreeMap) red-black ağacıdır.
  • splay tree: Her erişimde erişilen düğümü rotasyonlarla köke taşır — “son kullanılan hızlı” (self-adjusting).
  • treap: Rastgele öncelik + BST anahtarı; rotasyonla heap-özelliği korunur.

Hepsinde değişmez aynı: rotasyon \(O(1)\)’dir ve traversal sırasını korur; yalnız hangi düğümde tetiklendiğinin politikası farklıdır.

Tek cümle: rotasyonu öğrenmek tek bir ağacı değil, kendini-dengeleyen ağaç ailesinin tamamını öğrenmektir — fark, kuralda; ilkel hep aynı.

11.8 AVL / Yükseklik Dengesi

Hangi denge kuralı? Her düğüm için skew tanımla:

\[\text{skew}(\text{node}) = \text{height}(\text{node.right}) - \text{height}(\text{node.left})\]

AVL kuralı: her düğümde skew \(\in \{-1, 0, +1\}\) — yani sol ve sağ alt ağaç yükseklikleri en fazla 1 fark eder.

“skew of the node — I want this to always be minus 1, 0, or plus 1.” — Demaine, 35:11

Şekil 11.5 skew tanımını dört mini ağaç üzerinde gösterir: üçü kural içinde (\(-1, 0, +1\)), biri ihlal (\(+2\)).

Şekil 11.5: AVL kuralı — her düğümde skew ∈ {−1, 0, +1} (L7 §7; Demaine 35:11). Dört mini ağaç (skew = h(sağ) − h(sol), motordan okunur): (a) sol 1 yüksek → skew = 0 − 1 = −1, AVL-OK; (b) iki taraf eşit → skew = 0 − 0 = 0, AVL-OK; (c) sağ 1 yüksek → skew = 1 − 0 = +1, AVL-OK; (d) sağ 2 yüksek → skew = 1 − (−1) = +2, İHLAL (kalın slate çerçeve) → rotasyon gerek. İlk üç panel amber ONAY çerçevesi, dördüncü kalın slate çerçeve. Yükseklikler height alanından okunur (augmentation) → skew O(1); |skew| = 2 olunca ata yolunda rotasyon onarır.

11.9 Yükseklik Dengesi → Denge

Çalışılan Örnek — neden \(h \le 2 \log n\)? En az dengeli yükseklik-dengeli ağacı düşün: her düğümde sağ, soldan 1 yüksek. Yükseklik \(h\) olan böyle bir ağaçtaki minimum düğüm sayısı \(N_h\):

\[N_h = N_{h-1} + N_{h-2} + 1\]

Bu Fibonacci benzeri bir yinelemedir (\(+1\) olmadan tam Fibonacci); Fibonacci sayıları altın oran kuvvetiyle, yani üstel büyür. Üstel alt sınırı basitçe görmek için: \(N_{h-1} \ge N_{h-2}\) olduğundan \(N_h > 2 \cdot N_{h-2}\); bu da \(N_h \ge 2^{h/2}\) verir.

“It’s like Fibonacci numbers… Fibonacci numbers grow as a golden ratio to the n… this is exponential.” — Demaine, 39:48

\(N_h\) düğüm sayısı \(h\)’de üstel olduğundan, \(h\) düğüm sayısında logaritmiktir: \(h \le 2 \log n\). Yani AVL ağaçları her zaman dengelidir (gereken seviye sayısının en çok iki katı).

“h is at most 2 log n. So AVL trees are always quite balanced.” — Demaine, 42:09

Şekil 11.6 bunu iki panelde gösterir: solda build_fibonacci_tree(4) (\(h = 4\), \(n = N_4 = 12\)), sağda \(N_h\) dizisinin \(2^{h/2}\) alt sınırına karşı üstel büyümesi.

Şekil 11.6: En az dengeli AVL = Fibonacci ağacı → yükseklik h ≤ 2 log n (L7 §8; Demaine 42:09). Sol panel: build_fibonacci_tree(4) — h = 4, n = N₄ = 12; her düğümde sağ alt ağaç soldan TAM 1 yüksek (en az dengeli yükseklik-dengeli ağaç, sağ-ağır kademeli); in-order 0..11; en derin yol (sağ omurga, h + 1 = 5 düğüm) amber vurgulu. Sağ panel (semilog): Nₕ noktaları (motor dizisi [1, 2, 4, 7, 12, 20, 33, 54], h = 0..7) + alt sınır 2^(h/2) (amber kesikli); aradaki taralı bölge ÜSTEL büyümeyi gösterir; her h için Nₕ ≥ 2^(h/2). Nₕ = Nₕ₋₁ + Nₕ₋₂ + 1 (Fibonacci-benzeri) → düğüm sayısı h’de ÜSTEL → tersi: yükseklik logaritmik, h ≤ 2 log n.
İpucuBuilder Notu — Üstel Düğüm = Logaritmik Yükseklik

Bu, analiz disiplininin saf bir örneğidir: bir yapının yükseklik garantisi, “en kötü durumda en az kaç düğüm gerekir” sorusunu cevaplamaktan gelir.

  • Mantık zinciri: “yükseklik \(h\) için minimum düğüm \(N_h\) üstel” ⟹ “\(n\) düğüm en çok logaritmik yükseklik üretir”. Üstel alt sınır (düğüm tarafında) doğrudan logaritmik üst sınıra (yükseklik tarafında) çevrilir.
  • Aynı kalıp her yerde: ikili arama ağacının \(\Omega(\log n)\) karşılaştırma alt sınırı (karar ağacı yaprak sayısı \(\ge n+1\)), heap’in \(\log n\) yüksekliği, B-tree’nin \(\log_B n\) derinliği — hepsi “az düğümle çok yükseklik yapılamaz” argümanının çeşitlemeleridir.
  • Builder dersi: Bir veri yapısının hız garantisini ispatlamak istiyorsan, çoğu zaman doğrudan zamanı değil, boyut/yükseklik arasındaki üstel ilişkiyi sınırlarsın.

Tek cümle: \(h \le 2 \log n\)” bir hesaplama değil, bir sayma argümanıdır — en az dengeli ağacın bile üstel düğüm istemesi, yüksekliği logaritmaya hapseder.

11.10 Yükseklik de Bir Alt Ağaç Özelliği

Dengeyi kontrol etmek için her düğümün yüksekliğini bilmeliyiz. İyi haber: yükseklik bir alt ağaç özelliğidir:

\[\texttt{node.height} = 1 + \max(\texttt{node.left.height}, \texttt{node.right.height})\]

“node.height equals 1 plus max of node.left.height and node.right.height.” — Demaine, 43:33

Bu da \(O(1)\) güncelleme kuralıdır → her düğümün yüksekliğini (ve dolayısıyla skew’ini) zenginleştirmeyle tutabiliriz. (Rotasyon sırasında da etkilenen düğümlerin yükseklik/size alanları güncellenmelidir.)

11.11 Rotasyonlarla Dengeyi Koruma

Insert/delete bir yaprak ekler/siler → bazı ataların skew’i \(\pm 2\) olabilir (denge bozulur). Ata yolunu alttan yukarı kontrol et, en alttaki dengesiz düğümü \(x\) bul (skew \(= \pm 2\)). Yaprak değişimi yüksekliği yalnızca 1 değiştirdiğinden, bozulma da tam \(\pm 2\)’dir. \(y = x\)’in (yüksek taraftaki) çocuğu olsun; üç durum:

  • Durum 1-2 (skew(y) = +1 veya 0): Tek rotasyon (\(x\) üzerinde) dengeyi geri getirir.
  • Durum 3 (skew(y) = −1): Tek rotasyon işi kötüleştirir; çift rotasyon gerekir (önce \(z = y\)’nin çocuğu üzerinde, sonra \(x\) üzerinde). Ezberlenmesi gereken tek özel durum budur.

Her düzeltme \(O(1)\) (sabit sayıda işaretçi); ama bir düzeltme kökün yüksekliğini değiştirebileceğinden, yukarı çıkıp parent’ı da kontrol ederiz (ve zenginleştirmeleri güncelleriz). Toplam \(O(h) = O(\log n)\) sonra yükseklik dengesi geri gelir; böylece tüm işlemler \(O(\log n)\) olur.

Şekil 11.7 Durum 3’ü deterministik bir senaryoda (\(x = 10\), \(y = 30\), \(z = 20\); skew(x) \(= +2\), skew(y) \(= -1\)) üç karede gösterir: tek rotasyonun neden yetmediği, sonra çift rotasyonun (\(z\) sonra \(x\)) dengeyi nasıl geri getirdiği — traversal \([5, 10, 15, 20, 25, 30, 40]\) üç karede de değişmez.

Şekil 11.7: Durum 3 — tek rotasyon yetmez: çift rotasyon, right_rotate(30) → left_rotate(10) (L7 §10, İMZA figür). Deterministik build_case3_tree (motordan): skew(x = 10) = +2, skew(y = 30) = −1. Kare 1 (başlangıç): x = 10 kök, skew = +2 (kalın slate çerçeve = İHLAL); sağ çocuk y = 30, skew = −1; x SAĞA ağır ama y SOLA ağır → tek rotasyon yetmez. Kare 2 (adım 1): right_rotate(y = 30) sonrası — z = 20 yukarı geldi, 30 onun SAĞINA indi; artık 10 ve sağ çocuk 20 aynı yöne ağır. Kare 3 (adım 2): left_rotate(x = 10) sonrası — z = 20 KÖK (amber dolgu), 10 ve 30 çocukları, ağaç dengeli (DENGE GERİ GELDİ). HER karenin altında AYNI in-order şeridi [5, 10, 15, 20, 25, 30, 40]. Tek left_rotate(10) işi KÖTÜLEŞTİRİRDİ — ezberlenecek tek özel durum (Demaine Durum 3); motor doğrulaması: rebalance_node sonrası kök 20, check_avl_invariants True.

11.12 Bu Dersin Özeti

  1. Dizi ağacı: subtree_at ile \(i\). öğe; \(n_\ell\) = node.left.size ile boyut-temelli ikili arama; \(O(h)\).
  2. Alt ağaç zenginleştirme: çocuklardan \(O(1)\) hesaplanan özellik (size, height); insert/delete sonrası ata yolunu güncelle.
  3. Tutulabilir: sum/min/max/size (aşağı-bakan); tutulamaz: index/depth (global).
  4. Rotasyon: traversal sırasını koruyarak (\(A, X, B, Y, C\)) yeniden dengeleme aracı.
  5. AVL / skew \(\in \{-1, 0, +1\}\): yükseklik dengesi.
  6. Yükseklik dengesi → \(h \le 2 \log n\): \(N_h\) Fibonacci-benzeri, üstel; \(h\) logaritmik.
  7. Dengeyi koru: en alttaki dengesiz düğümde 1 veya 2 rotasyon; \(O(\log n)\).
ÖnemliTek Bir Cümle

İkili ağaca size/height zenginleştirmesi ekleyip, AVL skew kuralını rotasyonla korursak, \(h = O(\log n)\) garanti olur ve tüm sequence/set işlemleri \(O(\log n)\)’e iner.

11.13 Kontrol Soruları

Cevap: size aşağı bakar: bir düğümün boyutu yalnızca çocuklarının boyutlarından (node.left.size + node.right.size + 1) hesaplanır; başka bir yere düğüm eklemek bu alt ağacı değiştirmez. İndeks ise globaldir: bir düğümün indeksi, solundaki tüm düğümlere (alt ağaç dışındakiler dahil) bağlıdır; başa tek bir ekleme tüm indeksleri kaydırır. Sadece aşağı-bakan özellikler, ata yolunu \(O(h)\)’de güncelleyerek korunabilir.

Cevap: \(y\)’nin sol çocuğu \(x\), alt ağaçlar \(A\) (\(x\)’in solu), \(B\) (\(x\)’in sağı), \(C\) (\(y\)’nin sağı) olsun. Rotasyon öncesi traversal: \(A, X, B, Y, C\). right_rotate(y) sonrası \(x\) yukarı, \(y\) aşağı geçer; \(B\), \(y\)’nin soluna bağlanır — ama traversal yine \(A, X, B, Y, C\)’dir. Sıra korunduğu için BST/sequence anlamı bozulmaz; yalnızca düğümlerin derinlikleri değişir, bu da dengeleme imkânı verir.

Cevap: En az dengeli AVL ağacında (her düğüm skew \(\pm 1\)) yükseklik \(h\) için minimum düğüm \(N_h = N_{h-1} + N_{h-2} + 1\) (Fibonacci benzeri). \(N_{h-1} \ge N_{h-2}\) olduğundan \(N_h > 2 \cdot N_{h-2}\)\(N_h \ge 2^{h/2}\). Düğüm sayısı \(h\)’de üstel olduğundan, \(h\) düğüm sayısında logaritmiktir: \(h \le 2 \log n\). Yani en kötü AVL ağacı bile, optimumun en çok iki katı yüksekliktedir.

Cevap: Yükseklik bir alt ağaç özelliği olduğundan, bir yaprak eklendiğinde yalnızca o yaprağın atalarının yüksekliği (ve skew’i) değişebilir — diğer alt ağaçlar dokunulmaz. Bu ata yolu \(O(\log n)\) uzunluğundadır. Yaprak ekleme yüksekliği yalnızca 1 değiştirir, dolayısıyla bozulma tam \(\pm 2\)’dir; en alttaki dengesiz düğümde tek (Durum 1-2) ya da çift (Durum 3) rotasyon dengeyi geri getirir. Yukarı çıkarken her atayı kontrol ederiz, ama her biri sabit sayıda rotasyon ister → \(O(\log n)\).

11.14 Egzersizler

Egzersiz 1. Bir dizi ağacında subtree_at(node, i) algoritmasını, \(n_\ell\) = node.left.size kullanarak elle bir örnek üzerinde yürüt (\(i < n_\ell\), \(i = n_\ell\), \(i > n_\ell\) üç durumunu da göster).

Egzersiz 2. node.size güncelleme kuralının insert (yaprak ekleme) sonrası neden yalnızca \(O(h)\) atayı etkilediğini tümevarımla göster.

Egzersiz 3. “Alt ağaçtaki maksimum anahtar” bir alt ağaç özelliği midir? Güncelleme kuralını yaz. “Alt ağaçtaki ikinci en küçük anahtar” için ne olur?

Egzersiz 4. Python’da bir AVL düğümü için height ve skew güncellemesini yaz:

def update(node):
    lh = node.left.height if node.left else -1
    rh = node.right.height if node.right else -1
    node.height = 1 + max(lh, rh)
    node.skew = rh - lh

Egzersiz 5. AVL’de Durum 3 (skew(y) = −1) neden tek rotasyonla çözülmez? Çift rotasyonun (önce \(z\) üzerinde, sonra \(x\) üzerinde) traversal sırasını koruduğunu, iki tekil rotasyona indirgenerek olduğunu açıkla.

11.15 Sonraki Ders İçin Hazırlık

Ders 12 (L8): İkili Yığınlar (Binary Heaps)

Erik Demaine ile, öncelik kuyruğu (priority queue) arayüzüne ve onu çözen ikili yığına geçiyoruz: en büyük (veya en küçük) öğeyi \(O(\log n)\)’de çek/ekle. AVL’nin tam gücüne gerek olmayan, diziye gömülü zarif bir dengeli-ağaç. (Not: ders akışında araya Problem Oturumu 4 girer — kitap düzeninde bu, araya giren Ders 11 (PS4)’tür; İkili Yığınlar onu izleyen Ders 12’dir.)

UyarıDers 12 (L8) Öncesi Yapılacak
  • Bu dersin egzersizlerini, özellikle Egzersiz 4’ü (AVL update) çöz.
  • Üç fikri (subtree_at, augmentation, rotation) ve nasıl \(O(\log n)\) verdiklerini ezberden anlat.
  • Ana cümleyi tekrar oku: “AVL skew kuralını rotasyonla korursak, \(h = O(\log n)\) garanti olur.”

11.16 Anahtar Kavramlar (Cheat Sheet)

Kavram Tanım Sayfada
subtree_at(node, i) \(i\). öğe; \(n_\ell\) ile boyut-temelli ikili arama; \(O(h)\) Böl. 3
Alt ağaç özelliği Çocuklardan \(O(1)\) hesaplanan, aşağı-bakan nicelik Böl. 4
size güncelleme node.size = node.left.size + node.right.size + 1 Böl. 4
Tutulamaz index, depth (global; tüm ağaca bağlı) Böl. 5
Rotasyon Traversal’ı (\(A, X, B, Y, C\)) koruyan dengeleme Böl. 6
skew height(sağ) − height(sol); AVL: skew \(\in \{-1, 0, +1\}\) Böl. 7
Yükseklik dengesi \(N_h\) Fibonacci-benzeri üstel → \(h \le 2 \log n\) Böl. 8
Dengeyi koru En alttaki dengesizde 1-2 rotasyon; \(O(\log n)\) Böl. 10

11.17 Builder ve OMSCS Bağlantıları

İpucu6 köprü

Bu ders, “dengeyi nasıl garanti ederiz ve zenginleştirme ile ne kazanırız” sezgisini kurar — köprülerin özeti:

  1. Dengeli ağaç (AVL/red-black) → veritabanı indeksleri ve dosya sistemleri (B-tree, B+-tree): disk-dostu denge; çoğu SQL motorunun varsayılan indeksi bir dengeli ağaçtır (hash/GIN gibi özel türler ayrı uzmanlık).
  2. Subtree augmentation (size) → order-statistics tree: “rank(x)” ve “\(k\). en küçük” sorguları \(O(\log n)\).
  3. Rotasyon → tüm kendini-dengeleyen ağaçların (red-black, splay, treap) ortak ilkel işlemi.
  4. Aşağı-bakan vs global özellik → genel tasarım: bir niceliği verimli tutmak, onun yerel (kompozisyonel) olmasına bağlıdır.
  5. Fibonacci → log yükseklik → analiz disiplini: bir yapının garantisi, en kötü durum boyutunu (üstel düğüm) sınırlamaktan gelir.
  6. Traversal sırası = değişmez → her ağaç işleminin doğruluğu, korunan bir değişmezle (sıra, BST özelliği) ispatlanır.

ÖnemliTek bir şey alıp gideceksen

İkili ağaç tek başına \(O(h)\)’dir; onu güçlü kılan iki ekleme — size/height zenginleştirmesi (\(i\). öğe, denge bilgisi) ve rotasyon (sırayı bozmadan dengeleme). AVL skew kuralı bunları birleştirip \(h = O(\log n)\) garanti eder; gerisi her yerde \(O(\log n)\)’dir.