13  İkili Yığınlar (Binary Heaps)

Öncelik kuyruğu (insert + delete_max) = set’in alt kümesi; complete binary tree diziye örtük gömülür (left 2i+1, right 2i+2, parent (j−1)//2); max-heap özelliği + heapify up/down O(log n); yerinde heapsort O(n log n) ve doğrusal build = yüksekliklerin toplamı = O(n)

NotBölüm bilgisi

13.1 Bu Derste Ne Var?

Ders 10 (L7) AVL ağaçlarıyla her sequence/set işlemini \(O(\log n)\)’e indirdi. Bugün, AVL’nin basitleştirilmiş bir hâlini kuruyoruz: ikili yığın (binary heap). Aynı \(O(\log n)\) sınırlarını verir ama iki üstünlüğü vardır — doğrusal-zaman build ve, asıl önemlisi, yerinde (in-place) sıralama (heapsort).

“Today, we’re going to cover a different kind of tree-like data structure called a heap — a binary heap. It’s going to let us solve sorting problem in a new way.” — Demaine, 0:19

Üç temel kavram bu derste yan yana gelir:

  1. Öncelik kuyruğu (priority queue) — set arayüzünün alt kümesi: insert + delete_max; bu kısıtlama yeni güç verir.
  2. Complete binary tree ↔︎ dizi — yığın, diziye gömülü tam-ağaçtır (işaretçisiz, örtük; index aritmetiği).
  3. Max-heap özelliği + heapify — her düğüm çocuklarından büyük-eşit; ekle/sil heapify up/down ile \(O(\log n)\).
flowchart TD
    A["Ders 12 (L8): İkili Yığınlar"] --> PQ["Öncelik kuyruğu<br/>set arayüzünün alt kümesi"]
    PQ --> PQ1["insert + delete_max<br/>az söz veren arayüz = çok güç"]
    A --> CT["Complete binary tree ↔ dizi<br/>örtük, işaretçisiz"]
    CT --> CT1["index aritmetiği<br/>sol 2i+1, sağ 2i+2, parent (j−1)//2"]
    CT --> CT2["yükseklik ⌈log n⌉<br/>rotasyon gerekmez"]
    A --> MH["Max-heap özelliği + heapify<br/>her düğüm çocuklarından büyük-eşit"]
    MH --> MH1["maksimum kökte<br/>heapify up/down ile O(log n)"]
    A --> HS["Heapsort + doğrusal build"]
    HS --> HS1["yerinde, prefix yığın<br/>O(n log n) tek in-place"]
    HS --> HS2["doğrusal build<br/>yüksekliklerin toplamı = O(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
    class A root
    class PQ,CT,MH,HS branch
    class PQ1,CT1,CT2,MH1,HS1,HS2 leaf
Şekil 13.1: Ders 12’nin (L8) kavram haritası: kök = ikili yığın. Dört dal — (1) öncelik kuyruğu, set arayüzünün alt kümesidir (insert + delete_max); daha az söz veren arayüz daha güçlü optimizasyon açar. (2) complete binary tree, diziye örtük (işaretçisiz) gömülür; düğüm bağları yalnız index aritmetiğiyle bulunur (left 2i+1, right 2i+2, parent (j−1)//2) → yükseklik ⌈log n⌉, rotasyon gerekmez. (3) max-heap özelliği (her düğüm çocuklarından büyük-eşit, maksimum kökte) heapify up/down ile korunur, insert/delete_max O(log n). (4) heapsort yerinde (prefix yığın) ve O(n log n); doğrusal build ise yüksekliklerin toplamıdır = O(n). Sonuç: öncelik kuyruğu + bedava in-place sıralama.
İpucuBuilder Notu — Sadeleştirme = Güç

İkili yığın, AVL’nin basitleştirilmiş hâli — tüm set yerine yalnızca “maksimumu bul/sil” istediğimiz için, complete binary tree’yi (rotasyonsuz!) koruyabiliriz. Az söz veren bir arayüz, daha güçlü optimizasyon imkânı açar.

  • Geriye → Ders 10 (AVL): AVL keyfi BST şekliyle rotasyon gerektirir; yığın şekli \(n\) tarafından zaten sabittir → rotasyon yok, yalnız heapify (takas).
  • İleriye → graph algoritmaları: Dijkstra ve Prim, öncelik kuyruğunu (yığını) doğrudan kullanır — “en yakın sıradakini al” mantığı.
  • İleriye → sistem: router paket önceliği, işletim sistemi process scheduling, olay-tabanlı simülasyon hep öncelik kuyruğudur.
  • İleriye → heapsort: \(O(n \log n)\) ve in-place — ek bellek ayıramayan ortamlarda (gömülü, çekirdek) merge sort’a tercih edilir.

Tek cümle: Öncelik kuyruğunu, diziye gömülü dengeli bir tam-ağaçla (yığın) çözersek, ekle/sil \(O(\log n)\) olur ve yerinde \(O(n \log n)\) sıralama (heapsort) bedava gelir.

13.2 1. Öncelik Kuyruğu Arayüzü

Öncelik kuyruğu, öğeleri anahtarlarına (önceliklerine) göre tutar ve iki temel işlem sunar: insert (öğe ekle) ve delete_max (en yüksek öncelikli öğeyi sil ve döndür). Bu, set arayüzünün bir alt kümesidir — ve alt kümeler ilginçtir, çünkü daha basit/hızlı çözülebilirler.

“priority queue… This is a subset of the set interface.” — Demaine, 0:40

Motivasyon her yerde: router’da paket önceliği, işletim sisteminde hangi process’i çalıştıracağını seçmek, olayları zaman sırasına göre işlemek — ve bu sınıfta ileride çizge algoritmaları.

13.3 2. Set AVL ile Çözüm

Set AVL ağacı bu işlemleri zaten yapar: insert/delete_max \(O(\log n)\), build \(O(n \log n)\) (önce sıralama gerekir). find_max’i bir alt ağaç zenginleştirmesiyle (her düğümde alt ağacın maksimum anahtarı) \(O(1)\)’e bile indirebiliriz.

“set AVL is our most powerful data structure.” — Demaine, 3:33

Yani aslında “işimiz bitti”. Ama bugün ikili yığın öğreneceğiz: AVL kadar güçlü değil, sadece priority queue’yu çözüyor — ama daha basit, build’i bir log faktör hızlı, ve in-place sıralama veriyor.

13.4 3. Priority Queue Sort

Öncelik kuyruğu arayüzünü gerçekleştiren herhangi bir yapıdan bir sıralama algoritması doğar: tüm öğeleri ekle, sonra hepsini delete_max ile çıkar. delete_max büyükten küçüğe verdiği için, ters-sıralı çıkar; lineer zamanda ters çevir → sıralı.

“given any data structure that implements a priority queue interface… I can make a sorting algorithm. Insert all the items, delete all the items.” — Demaine, 8:29

Çalışma süresi: \(T_{\text{build}}(n) + n \cdot T_{\text{delete\_max}}\) — veya \(n \cdot (T_{\text{insert}} + T_{\text{delete\_max}})\). Hangi yapıyı koyarsan, o sıralamayı alırsın.

13.5 4. Üç Sıralama: Birleştirici Çerçeve

Priority queue sort, daha önce gördüğümüz üç sıralamayı tek çerçevede birleştirir:

  • Set AVL (insert/delete \(O(\log n)\)) → AVL sort, \(O(n \log n)\).
  • Sırasız dizi (insert \(O(1)\), delete_max \(O(n)\) — maksimumu tara, sona taşı) → selection sort, \(O(n^2)\).
  • Sıralı dizi (insert \(O(n)\) — kaydır, delete_max \(O(1)\) — son öğe) → insertion sort, \(O(n^2)\).

“arrays give us selection sort… insertion sort.” — Demaine, 11:53

Selection ve insertion sort in-place (sabit ek alan) ama \(O(n^2)\); AVL sort ve merge sort \(O(n \log n)\) ama in-place değil. Bugünkü hedef: \(n \log n\) ve in-place — ikili yığın ile (heapsort).

Şekil 13.2 bunu tek çerçevede toplar: aynı “hepsini insert, sonra hepsini delete_max” tarifi; hangi veri yapısını koyarsan o sıralama doğar. Hedef satır 4 — ikili yığın, iki işlemi de \(O(\log n)\) dengeler ve sonuç hem \(O(n \log n)\) hem yerinde.

Şekil 13.2: Öncelik kuyruğu sıralaması — birleştirici çerçeve: PQ’yu hangi yapı uygularsa o sıralama doğar (L8 §3-4). Üst kutu TEK tarifi anlatır: tüm öğeleri insert et → sonra hepsini delete_max ile çek (çekiş sırası = azalan sıralı). Altta 4 satır yapı → sıralama: (1) sırasız dizi [insert O(1) / delete_max O(n)] → Selection Sort O(n²); (2) sıralı dizi [insert O(n) / delete_max O(1)] → Insertion Sort O(n²); (3) küme AVL ağacı [O(log n)/O(log n)] → AVL Sort O(n log n); (4) İKİLİ YIĞIN [O(log n)/O(log n)] → HEAPSORT O(n log n) + IN-PLACE rozeti (amber vurgu, hedef satır). Dizi PQ’lar bir işlemi ucuz yapar ama diğerini O(n)’e iter → O(n²); yığın iki işlemi de O(log n) dengeler → O(n log n). Motor kanıtı: Q=[]; insert [4,1,7,3,9,2,6]; drain ×7 = [9,7,6,4,3,2,1] = sorted(desc).

13.6 5. Hedef: n log n + Yerinde (Complete Binary Tree)

In-place olmak için, \(n\) öğeyi tam \(n\) dizi gözünde tutmalıyız. \(\log n\) performans için de bir ağaç gerekir. Çözüm: ağacı bir diziye gömmek. Hangi ağaç? Complete binary tree (tam ikili ağaç): her \(i\). derinlikte \(2^i\) düğüm, son seviye hariç; son seviye sola yaslı (left-justified).

“these two properties together is what I call a complete binary tree.” — Demaine, 17:10

Complete binary tree her zaman dengelidir — yüksekliği tam \(\lceil \log n \rceil\) (mümkün olan en iyi). Rotasyona gerek yoktur.

13.7 6. Complete Binary Tree ↔︎ Dizi

Tam ikili ağaç ile dizi arasında bir birebir eşleme (bijection) vardır: düğümleri derinlik sırasında (level order — A, sonra B, C, sonra D, E, F, G…) diziye yaz. \(n\) verilince tek bir ağaç şekli vardır (yukarıdan aşağı, soldan sağa dolar).

“between complete binary trees and arrays is a bijection.” — Demaine, 18:33

Bu yüzden işaretçi saklamaya gerek yok — sadece dizi: örtük veri yapısı (implicit data structure).

“This is what we call an implicit data structure… no pointers, just an array of the n items.” — Demaine, 20:28

Çalışılan Örnek — index aritmetiği. İşaretçileri index hesabıyla bul. \(i\). düğüm için:

  • Sol çocuk: \(2i + 1\).
  • Sağ çocuk: \(2i + 2\) (sol çocuğun sağ kardeşi).
  • Parent (\(j\) çocuksa): \((j - 1) // 2\) (tamsayı bölme).

Örnek: index 4’teki düğümün sol çocuğu \(2 \cdot 4 + 1 = 9\); sağ çocuğu \(2 \cdot 4 + 2 = 10\) — dizi boyutunu aşıyorsa o çocuk yoktur. Ters yön de tutarlı: \(\text{parent}(9) = (9 - 1) // 2 = 4\). Tüm bunlar sabit zaman; complete binary tree’nin özel yapısı sayesinde mümkün.

Şekil 13.3 bu bijeksiyonu somutlar: 11 düğümlü bir max-heap, hem ağaç hem dizi olarak; index 4 düğümü amber dolgu, çocukları 9 ve 10 amber çerçeve, formül kutusunda \(\text{left}(4) = 9\), \(\text{right}(4) = 10\), \(\text{parent}(9) = 4\) doğrulanır.

Şekil 13.3: Complete binary tree ⟷ dizi: işaretçisiz örtük yapı (L8 §5-6, İMZA figür). Üst: 11 düğümlü complete binary tree, 4 düzey, son düzey SOLA YASLI (etiketli); her düğüm dairesinde değer, yanında index rozeti (i=0..10). Alt: aynı 11 değerin dizi şeridi (her hücre altında index). Her ağaç düğümünden dizi hücresine ince bağ çizgisi (level-order bijeksiyon). index 4 düğümü amber DOLGU; çocukları index 9 ve 10 amber ÇERÇEVE; sağda formül kutusu: left(4) = 2·4+1 = 9, right(4) = 2·4+2 = 10, parent(9) = (9−1)//2 = 4, parent(10) = (10−1)//2 = 4. Düğüm bağları YALNIZ index aritmetiğiyle bulunur — işaretçi (next/left/right) YOK. Yükseklik = ⌈log n⌉ → işlemler O(log n); ağaç dolu ve sola yaslı → dengeleme rotasyonu gerekmez (BST/AVL aksine). Motor: build_heap_linear([25,16,21,5,12,18,19,1,3,9,7]) zaten max-heap; is_max_heap True; heap_left(4)=9, heap_right(4)=10, heap_parent(9)=4, heap_parent(10)=4 (Demaine 20:28).

13.8 7. Max-Heap Özelliği

Son bir kural: max-heap özelliği — her düğüm \(i\) için \(Q[i].\text{key} \ge Q[j].\text{key}\) (\(j\) sol veya sağ çocuk). Yani her düğüm iki çocuğundan da büyük-eşittir; iki çocuğun birbirine göre sırası umursanmaz (BST’den farkı budur).

“the max-heap property: Q[i] is greater than or equal to Q[j] for both children.” — Demaine, 26:02

Önemli lemma: bu özellik her yerde sağlanıyorsa, her düğüm alt ağacındaki tüm düğümlerden büyük-eşittir (geçişlilikle: aşağı yolda her kenar anahtarı azaltmaz). Dolayısıyla maksimum kökte durur.

“every node i is greater than or equal to all nodes in its subtree.” — Demaine, 27:39

13.9 8. insert ve max_heapify_up

insert(x): yeni öğeyi yalnızca dizinin sonuna ekleyebiliriz (son yaprak, \(\text{index} = \text{size} - 1\)). Ama bu max-heap özelliğini bozabilir → düzelt.

Çalışılan Örnek — max_heapify_up. Eklenen düğümden başla. Parent’ının anahtarı çocuktan küçükse (kural ihlali), ikisini takas et; sonra parent ile özyinele (yukarı çık). Öğe en fazla kök seviyesine kadar “kabarır”. Yalnızca bu tek öğe yanlış yerde olduğundan, hareket durduğunda max-heap özelliği sağlanmıştır.

“max_heapify_up… it goes up one… the running time is the height of the tree, which is log n.” — Demaine, 36:06

Süre: ağaç yüksekliği = \(O(\log n)\).

Şekil 13.4 bu kabarmayı somut bir örnekte gösterir: \([9, 5, 8, 3, 1]\) yığınına 10 eklenir; 10 sona (index 5) konur, parent 8’den büyük olduğu için takas edilir (index 2), sonra parent 9’dan da büyük olduğu için bir kez daha takas edilir — toplam 2 kabarma — ve 10 köke ulaşır.

Şekil 13.4: insert + kabarma (heapify_up): yeni öğe sona eklenir, parent’ından büyükçe yukarı süzülür (L8 §8). Üç panel yan yana; her panel: yığının complete-tree çizimi (6 düğüm) + altında o anki dizi şeridi. Motor izi heapify_up_trace([9,5,8,3,1], 10): (1) 10 SONA eklenir index 5 (tek geçerli yer) → dizi [9,5,8,3,1,10]; parent index 2 = 8 < 10 → İHLAL, kabarma gerekir. (2) 8 ↔︎ 10 takas → 10 yukarı index 2; dizi [9,5,10,3,1,8]; parent index 0 = 9 < 10 → hâlâ İHLAL. (3) 9 ↔︎ 10 takas → 10 KÖKTE index 0; dizi [10,5,9,3,1,8]; max-heap ONARILDI. Kabaran öğe 10 amber dolgu; İHLAL eden kenar amber + ‘İHLAL’ etiketi. Her takas en fazla bir seviye çıkar → takas sayısı (2) ≤ ağaç derinliği = O(log n). Motor: final kök = 10, is_max_heap(final) True (Demaine 36:06).

13.10 9. delete_max ve max_heapify_down

delete_max: maksimum kökte (index 0), ama dizide yalnızca son öğeyi verimli silebiliriz. Çözüm: kökü son yaprakla takas et, son öğeyi sil (delete_last). Şimdi köke küçük bir değer geldi → düzelt.

max_heapify_down: kökten başla; iki çocuktan büyüğüyle takas et (böylece her iki kenar da kuralı sağlar), sonra o çocukta özyinele (aşağı in). Yaprağa ulaşınca dur.

“Heapify down. We’re going to take that item and push it down… until max-heap property is satisfied.” — Demaine, 39:16

Süre yine \(O(\log n)\). (Yığında hiç rotasyon yok — yalnızca takas.)

Şekil 13.5 bu süzmeyi gösterir: \([10, 9, 8, 3, 1, 5]\) yığınında max 10 kökte; kök son yaprak 5 ile takas edilip 10 silinir; köke gelen 5, iki çocuk 9 ve 8’in büyüğü olan 9 ile takas edilir (1 süzme) ve kök 9 olur — final \([9, 5, 8, 3, 1]\), hâlâ max-heap.

Şekil 13.5: delete_max → aşağı süzme (heapify_down): kök↔︎son takas, sil, büyük çocukla süz (L8 §9, İMZA figür). Üç panel soldan sağa; motor izi heapify_down_trace([10,9,8,3,1,5]). (1) max kökte — kök 10 + son yaprak 5 amber dolgu, aralarında çift yönlü takas oku; max = 10 (yalnız kökte), son yaprak 5 yukarı taşınır; dizi-gömme sol 2i+1 · sağ 2i+2. (2) son öğe silindi → İHLAL — 10 çıkarıldı (soluk düğüm + dışarı ok), 5 kökte ama sol çocuk 9 > 5 → yığın özelliği bozuldu (kalın slate çerçeve); ara dizi [5,9,8,3,1]. (3) büyük çocukla takas → aşağı süz — 5 ↔︎ 9 takası (iki çocuk 9 ve 8’in BÜYÜĞÜ 9 seçilir, böylece her iki kenar da kuralı sağlar); final [9,5,8,3,1], 9 kök, ONARILDI. En fazla yükseklik kadar takas = O(log n); rotasyon YOK, yalnız takas. Motor: removed_max = 10, final kök = 9, is_max_heap(final) True (Demaine 39:16).

13.11 10. Yerinde Heapsort ve Doğrusal Build

In-place heapsort: Diziyi büyütüp küçültmek yerine, yığını dizinin bir önekinde (prefix) tut. insert = size’ı artır (sonraki A öğesini yığına kat); delete_max = size’ı azalt (son öğeyi düşür). Hiç yeniden boyutlandırma yok → her işlem en kötü durum \(O(1)\) ek. Tüm öğeleri yığına al, sonra delete_max ile çıkar; en büyük öğe sona gider → dizi yukarı sıralı olur.

“that is what’s normally called heapsort.” — Demaine, 48:05

Bu, \(n \log n\) ve in-place (bu sınıftaki tek böyle algoritma).

Şekil 13.6 tek dizi içinde prefix yığının küçülüp sıralı sonekin büyümesini gösterir: \([2, 7, 1, 9, 3, 6]\) önce doğrusal build ile \([9, 7, 6, 2, 3, 1]\) yığınına dönüşür; her adım kökü (max) prefix-sonu ile takas eder, yığını 1 küçültür, kökü süzer — çıktı \([1, 2, 3, 6, 7, 9]\).

Şekil 13.6: Yerinde heapsort (in-place): prefix yığın küçülür, sıralı sonek büyür (L8 §10, İMZA figür). 6 satır dizi şeridi, her satır 6 hücre = TEK dizi (in-place). Motor izi heapsort_trace([2,7,1,9,3,6]). Satır 1 = doğrusal build sonrası: tamamı yığın [9,7,6,2,3,1] (slate hücreler, SOL etiket ‘yığın’). Her sonraki satır: kök ↔︎ prefix-sonu takas oku → prefix yığın 1 hücre küçülür, kopan max sıralı soneke geçer (yeni amber hücre yıldızlı ★); yığın slate (SOL etiket), sonek amber (SAĞ etiket ‘sıralı’). Son satır: tamamı sıralı [1,2,3,6,7,9] (amber). Sağda kutu: ek bellek YOK, yığın + sıralı = AYNI dizi. Her adım kökü (max) yığının sonuna takas eder → sıralı soneğe katar, yığını 1 küçültür, kökü süzer; n log n VE yerinde (bu sınıfın tek böyle algoritması). Motor: build = [9,7,6,2,3,1], 6 adım, output = [1,2,3,6,7,9] (Demaine 48:05).

Doğrusal build: Öğeleri tek tek ekleyip yukarı-heapify yaparsan toplam derinliklerin toplamı = \(n \log n\). Bunun yerine, hepsini diziye koyup aşağıdan yukarıya heapify-down yap. Bu, yüksekliklerin toplamıdır ve şaşırtıcı biçimde \(O(n)\)’dir (yapraklar çok ama yükseklikleri küçük; kök yüksek ama tek).

“heapify down from the bottom up… that’s better. Because this is the sum of the heights of the nodes. And that turns out to be linear.” — Demaine, 49:24

Şekil 13.7 bu üstünlüğü ölçer: \(n = 15\) complete tree’de \(\Sigma\) derinlik \(= 34\) (tek tek insert, \(\approx n \log n\)) iken \(\Sigma\) yükseklik \(= 11\) (bottom-up build, \(\le 2n = 30\)); \(n = 1023\)’te uçurum büyür — 8194’e karşı 1013 (hâlâ \(\le 2046\)).

Şekil 13.7: Doğrusal build = yüksekliklerin toplamı, Σ yükseklik ≤ 2n = O(n) (L8 §10). Sol panel: n=15 complete tree (4 seviye); iç düğümlerin yanında d=derinlik (slate) + h=yükseklik (amber) rozetleri; yapraklar (h=0) amber dolgu; altta iki toplam kutusu: Σderinlik = 34 (tek tek insert ~ n log n, slate) vs Σyükseklik = 11 (bottom-up build = O(n), amber) + ‘11 ≤ 2n = 30’ etiketi; 8 yaprak hepsi h0 → yükseklik maliyeti sıfır. Sağ panel: büyüme grafiği n = 15, 127, 1023; Σderinlik (slate, n=1023 → 8194 fırlar ~ n log n) vs Σyükseklik (amber, n=1023 → 1013 doğrusal kalır) + 2n referans kesikli çizgi; n=1023’te UÇURUM 8194 ↔︎ 1013 vurgulanır. Yapraklar ÇOK ama yükseklikleri KÜÇÜK (h=0) — çok olandan az öde; bottom-up build O(n), tek tek insert ise n log n. Motor: complete_tree_depth_height_sums(15)=(34,11), (1023)=(8194,1013) (Demaine 49:24).

13.12 Bu Dersin Özeti

  1. Öncelik kuyruğu: insert + delete_max; set arayüzünün alt kümesi.
  2. Priority queue sort: ekle-hepsini + delete_max-hepsini → AVL/selection/insertion sort birleşir.
  3. Complete binary tree: her derinlik dolu, son seviye sola yaslı; yükseklik \(\lceil \log n \rceil\), dengeli.
  4. Dizi ↔︎ ağaç bijection: derinlik sırası; örtük (işaretçisiz); left \(2i+1\), right \(2i+2\), parent \((j-1)//2\).
  5. Max-heap özelliği: \(Q[i] \ge\) çocukları; maksimum kökte; düğüm \(\ge\) tüm alt ağacı.
  6. insert/delete_max: max_heapify_up / max_heapify_down (takas + özyinele); \(O(\log n)\).
  7. Heapsort: prefix yığın, in-place, \(O(n \log n)\); doğrusal build = yüksekliklerin toplamı = \(O(n)\).
ÖnemliTek Bir Cümle

İkili yığın, dengeli bir tam-ağacı diziye gömüp (işaretçisiz) max-heap özelliğini heapify ile korur; sonuç hem \(O(\log n)\) öncelik kuyruğu hem de yerinde \(O(n \log n)\) sıralama (heapsort).

13.13 Kontrol Soruları

Cevap: Yığın bir complete binary tree’dir — şekli \(n\) tarafından zaten benzersiz biçimde belirlenir (yukarıdan aşağı, soldan sağa dolu) ve her zaman dengelidir (yükseklik \(\lceil \log n \rceil\)). Şekil sabit olduğundan dengeleme (rotasyon) gerekmez; yalnızca anahtarların yerini (heapify up/down ile takas) düzeltiriz. AVL ise keyfi şekilli bir BST olduğundan, dengeyi korumak için rotasyon şarttır. Yığının bu lüksü, yalnızca priority queue (set’in alt kümesi) çözmesinden gelir.

Cevap: index 4’ün sol çocuğu \(2 \cdot 4 + 1 = 9\), sağ çocuğu \(2 \cdot 4 + 2 = 10\). index 9’un parent’ı \((9 - 1) // 2 = 4\) — tutarlı (9, 4’ün sol çocuğuydu). index 10’un parent’ı \((10 - 1) // 2 = 4\) (tamsayı bölme) — sağ çocuk da aynı parent’a döner. Bir çocuk index’i dizi boyutunu aşıyorsa o çocuk yoktur (yaprak).

Cevap: BST: sol alt ağaç \(<\) düğüm \(<\) sağ alt ağaç — yatay sıralama, traversal sırası anlamlı, find/range yapılır. Max-heap: düğüm \(\ge\) her iki çocuğu — yalnızca dikey (ata-torun) ilişki; iki çocuğun birbirine göre sırası umursanmaz. Heap, anahtarları sıralı tutmaz, sadece “maksimum köktedir” garantisi verir; bu yüzden find(k) veya find_next yapamaz, ama find_max/delete_max’i çok ucuz yapar.

Cevap: Tek tek insert + heapify-up, her öğe için derinlik kadar iş yapar; toplam = derinliklerin toplamı = \(O(n \log n)\) (çoğu öğe yapraktadır, derinliği \(\sim \log n\)). Bottom-up heapify-down ise her düğüm için yükseklik kadar iş yapar; toplam = yüksekliklerin toplamı. Yapraklar çoktur ama yükseklikleri 0-1; yüksek düğümler azdır. Bu ağırlıklı toplam \(O(n)\)’e yakınsar — “çok olandan az öde, az olandan çok öde”.

13.14 Egzersizler

Egzersiz 1. Verilen bir diziyi complete binary tree olarak çiz (derinlik sırası); index aritmetiğiyle her düğümün çocuklarını/parent’ını doğrula.

Egzersiz 2. Bir max-heap’e yeni bir maksimum öğe ekle ve max_heapify_up’ı adım adım yürüt (köke kadar kabarma).

Egzersiz 3. Bir max-heap’ten delete_max yap: kök-son takas, delete_last, max_heapify_down (büyük çocukla takas). Sonucun hâlâ heap olduğunu doğrula.

Egzersiz 4. Python’da örtük yığın için index aritmetiğini ve heapify_down’ı yaz:

def heapify_down(Q, i, n):
    while True:
        l, r = 2*i + 1, 2*i + 2
        big = i
        if l < n and Q[l] > Q[big]: big = l
        if r < n and Q[r] > Q[big]: big = r
        if big == i: return
        Q[i], Q[big] = Q[big], Q[i]
        i = big

Egzersiz 5. Heapsort’un neden in-place olduğunu (prefix yığın) açıkla. Merge sort neden in-place değildir? İkisinin de \(O(n \log n)\) olmasına rağmen hangi durumda heapsort tercih edilir?

13.15 Sonraki Ders İçin Hazırlık

Ders 13 (L9): Çizgeler ve BFS (Breadth-First Search)

Justin Solomon ile, veri yapılarından çizge (graph) algoritmalarına geçiyoruz: düğümler ve kenarlar, ve bir kaynaktan enine arama (BFS) ile ağırlıksız en kısa yollar. Öncelik kuyruğu, ilerideki ağırlıklı en kısa yollarda (Dijkstra) yeniden karşımıza çıkacak. (Not: ders akışında araya Problem Oturumu ve Quiz 1 tekrarı girer — kitap düzeninde Quiz 1 tekrarı araya giren Ders 14 (Quiz 1 Review)’tür.)

UyarıDers 13 Öncesi Yapılacak
  • Bu dersin egzersizlerini, özellikle Egzersiz 4’ü (heapify_down) çöz.
  • Üç fikri (complete tree ↔︎ array, max-heap özelliği, heapify) ve nasıl in-place heapsort verdiklerini ezberden anlat.
  • Ana cümleyi tekrar oku: “Dengeli tam-ağacı diziye gömüp heapify ile koru.”

13.16 Anahtar Kavramlar (Cheat Sheet)

Kavram Tanım Sayfada
Öncelik kuyruğu insert + delete_max; set’in alt kümesi Böl. 1
Priority queue sort Ekle-hepsini + delete_max → AVL/selection/insertion Böl. 3-4
Complete binary tree Her derinlik dolu, son seviye sola yaslı; yükseklik \(\lceil \log n \rceil\) Böl. 5
Dizi ↔︎ ağaç (örtük) left \(2i+1\), right \(2i+2\), parent \((j-1)//2\) Böl. 6
Max-heap özelliği \(Q[i] \ge\) çocukları; maksimum kökte Böl. 7
max_heapify_up/down Takas + özyinele; insert/delete_max \(O(\log n)\) Böl. 8-9
Heapsort Prefix yığın; in-place; \(O(n \log n)\) Böl. 10
Doğrusal build Bottom-up heapify-down = yüksekliklerin toplamı = \(O(n)\) Böl. 10

13.17 Builder ve OMSCS Bağlantıları

İpucu6 köprü

Bu ders, “az söz veren arayüz ne kadar güç açar ve örtük yapı ne kazandırır” sezgisini kurar — köprülerin özeti:

  1. Öncelik kuyruğu → Dijkstra/Prim (graph), event-driven simülasyon, OS scheduler, router QoS — her yerde “en öncelikliyi al”.
  2. Heapsort (in-place, \(n \log n\)) → bellek-kısıtlı sistemler (gömülü, çekirdek); ek tampon ayıramayan ortamlar.
  3. Örtük veri yapısı → cache-dostu tasarım: işaretçisiz dizi, bellek yerelliği yüksek (heap, segment tree).
  4. Complete tree ↔︎ array → segment tree / Fenwick tree’nin temeli; aynı index-aritmetiği indeksleme.
  5. Alt küme = daha fazla güç → API tasarım ilkesi: daha az söz veren arayüz, daha güçlü garanti/optimizasyon sunabilir.
  6. Yüksekliklerin toplamı = \(O(n)\) → amortize/ağırlıklı analiz sezgisi: “çok olandan az, az olandan çok öde”.

ÖnemliTek bir şey alıp gideceksen

İkili yığın, “her şeyi” değil yalnızca “maksimumu” istediğin için, dengeli bir tam-ağacı diziye işaretçisiz gömebilir ve rotasyonsuz korur. Bu kısıtlama iki armağan verir: doğrusal build ve — tek in-place \(O(n \log n)\) sıralaman olan — heapsort.