Bölüm 8: Öncelikli Kuyruklar ve Heap

Veri Yapıları
Öncelikli kuyruk ADTListe ile uygulamaİkili heap Dizi gösterimiUp-heap / down-heapHeap oluşturmaHeap sort
Sercan KÜLCÜ · Giresun Üniversitesi · Bilgisayar Mühendisliği

Giriş

Öğrenme Çıktıları

ADT modeli

Öncelikli kuyruğun temel işlemlerini ve kullanım alanlarını açıklamak.

İkili öbek

Heap düzeni ve tam ikili ağaç özelliğini dizi gösterimiyle ilişkilendirmek.

İşlemler

Ekleme, kökü çıkarma ve öbek oluşturma adımlarını uygulamak.

Maliyet analizi

İşlem maliyetlerini ve Heap Sort algoritmasını değerlendirmek.

Öncelikli Kuyruk ADT

Öncelikli Kuyruk (Priority Queue)

  • Her öğenin bir önceliği (anahtarı) vardır; öğeler öncelik sırasına göre çıkar.
  • Geliş sırası değil, öncelik belirleyicidir: ambulans trafikte öne geçer.
  • Öncelikli işlerin yönetiminde kullanılır: görev çizelgeleme, acil servis, olay simülasyonu.
  • En yüksek öncelikli öğeye bakmak O(1); onu çıkarmak ise uygulamaya bağlıdır (heap ile O(log n)).
Sıkışık trafikte araçlar kenara çekilmiş, ambulans açılan şeritten öne geçiyor.
Önce gelen değil, önceliği yüksek olan geçer.

Öncelikli Kuyruk ADT

Temel Kavramlar

Öğe = (anahtar, değer)Anahtar (key) önceliği, değer (value) asıl veriyi taşır.(1, "kalp krizi") · (4, "burkulma")
ÖncelikAnahtarlar karşılaştırılabilir olmalı (<, ≤). Genelde küçük anahtar = yüksek öncelik (min-öncelikli kuyruk).
En yüksek öncelikKuyruğun "önündeki" öğe: min-kuyrukta en küçük, max-kuyrukta en büyük anahtar.
Eşit öncelikEşit anahtarlı öğeler için FIFO sırası kendiliğinden garanti değildir; gerekiyorsa anahtara bir geliş sıra numarası eklenir.

Öncelikli Kuyruk ADT

Kuyruk mu, Öncelikli Kuyruk mu?

Acil servise sırasıyla dört hasta geliyor (küçük sayı = daha acil):

Geliş1.2.3.4.
Hasta (öncelik)Ali (3)Ece (1)Can (2)Naz (1)
Kuyruk (FIFO)AliEceCanNaz
Öncelikli kuyrukEceNazCanAli
Kuyruk (Bölüm 5)Çıkış sırası = geliş sırası. Önce gelen önce hizmet alır.
Öncelikli kuyrukÇıkış sırası = öncelik sırası. Ece ve Naz eşit (1); burada geliş sırasını koruduk.

Öncelikli Kuyruk ADT

Kullanım Alanları

İşletim SistemleriGörev (süreç) çizelgeleme: yüksek öncelikli süreç işlemciyi önce alır.kesme işleyici > arayüz > yedekleme
Çizge AlgoritmalarıDijkstra en kısa yol ve A* araması, sıradaki en yakın düğümü öncelikli kuyruktan alır (Bölüm 11).
Acil Durum YönetimiHasta triyajı ve olay yönetimi: en acil vaka önce ele alınır.
Veri SıkıştırmaHuffman kodlaması, her adımda en düşük frekanslı iki düğümü birleştirir.

Öncelikli Kuyruk ADT

Temel İşlemler

İşlemAnlamı
insert(k, v)Ekleme: öğe, önceliğine göre yerini alır.
removeMin()Çıkarma: en yüksek öncelikli öğeyi çıkarır ve döndürür.
min()Sorgulama (peek): öğeyi döndürür, çıkarmaz.
size()Öğe sayısı.
isEmpty()Kuyruk boş mu?
public interface PriorityQueue<K, V> {
    void insert(K key, V value);
    Entry<K, V> min();        // boşsa null
    Entry<K, V> removeMin();  // boşsa null
    int size();
    boolean isEmpty();
}

Max-öncelikli kuyrukta aynı işlemler max() ve removeMax() adını alır. Bu bölümün kod örnekleri, orijinal sunumdaki gibi max-heap (ekle, silMax) kullanır.

Öncelikli Kuyruk ADT

Örnek İşlem Dizisi (min-öncelikli)

İşlemDönen değerKuyruğun içeriği
insert(5, A){ (5,A) }
insert(9, C){ (5,A), (9,C) }
insert(3, B){ (3,B), (5,A), (9,C) }
min()(3,B){ (3,B), (5,A), (9,C) }
removeMin()(3,B){ (5,A), (9,C) }
insert(7, D){ (5,A), (7,D), (9,C) }
removeMin()(5,A){ (7,D), (9,C) }
removeMin()(7,D){ (9,C) }
removeMin()(9,C){ }
removeMin()null{ }  boş kuyruk

Liste ile Uygulama

Sırasız Liste ve Sıralı Liste

Sırasız liste (unsorted)
5 9 3 7 4 min için hepsi taranır ← ekle
  • insert: sona ekle → O(1)
  • min, removeMin: tüm listeyi tara → O(n)
Sıralı liste (sorted)
3 4 5 7 9 min 4 için yer aranır, kaydırılır
  • insert: doğru yeri bul → O(n)
  • min, removeMin: en küçük hep uçta → O(1)
Biri eklemede, diğeri çıkarmada hızlı. İkisini dengeleyen yapı: ikili heap (her ikisi de O(log n)).

Liste ile Uygulama

Dizi ve Bağlı Liste Temsili

Dizi temsili
  • Öğeler dizide tutulur; sıralı tutmak için ekleme sırasında öğeler kaydırılır (O(n)).
  • Öncelikli öğe dizinin başında tutulursa her çıkarmada tüm dizi sola kaydırılır: O(n).
  • Doğrusu: en öncelikli öğeyi dizinin sonunda tutmak → çıkarma O(1).
Bağlı liste temsili
  • Öğeler önceliklerine göre listedeki uygun konuma eklenir: yer arama O(n), bağlama O(1).
  • Öncelikli öğe listenin başındadır; çıkarma = baştan silme, O(1).
  • Kaydırma yok, ama her düğüm ek bir referans taşır.
baş 3 5 7 9 6 null

Liste ile Uygulama

Maliyet Karşılaştırması

İşlemSırasız listeSıralı listeİkili heap
size, isEmptyO(1)O(1)O(1)
insertO(1)O(n)O(log n)
minO(n)O(1)O(1)
removeMinO(n)O(1)O(log n)
n öğeyle doldurmaO(n)O(n log n)*O(n)**

* Önce sıralayarak.   ** Aşağıdan yukarıya heap oluşturma ile (bu bölümün sonunda).

n ekleme + n çıkarma: sırasız ve sıralı listede O(n²), heap'te O(n log n). n = 10⁶ için fark ≈ 50.000 kat.

İkili Heap

İkili Heap (Binary Heap)

Öncelikli kuyruğu uygulamak için en yaygın veri yapısıdır. İki koşulu birlikte sağlayan bir ikili ağaçtır:

1. Heap-sıra özelliğiHer düğüm, çocuklarından önce gelir: max-heap'te ebeveyn ≥ çocuk, min-heap'te ebeveyn ≤ çocuk. Bu yüzden en yüksek öncelikli öğe köktedir.
2. Tam ikili ağaç özelliğiSon düzey hariç tüm düzeyler dolu, son düzey soldan sağa dolar. Bu yüzden yükseklik ⌊log₂ n⌋ olur ve ağaç bir diziye boşluksuz yerleşir.
Ekleme ve çıkarma yalnızca kökten yaprağa uzanan tek bir yol üzerinde çalışır → O(log n). Heap, ikili arama ağacı değildir: kardeşler arasında sıra yoktur.

İkili Heap

Min-Heap ve Max-Heap

0739856
Min-Heap: kökte en küçük anahtar
anahtar(ebeveyn) ≤ anahtar(çocuk)
9362154
Max-Heap: kökte en büyük anahtar
anahtar(ebeveyn) ≥ anahtar(çocuk)
  • Sıra yalnızca ebeveyn–çocuk arasında geçerlidir: min-heap'te 7 ile 3 kardeştir, 7 > 3 olması sorun değildir.
  • Kökten herhangi bir yaprağa giden her yol sıralıdır (min-heap'te artan, max-heap'te azalan).

İkili Heap

Tam İkili Ağaç (Complete Binary Tree)

12345
Tam ✓
son düzey soldan dolu
12346
Tam değil ✗
son düzeyde boşluk var
12367
Tam değil ✗
son düzey sola yaslı değil
Yükseklikd. düzeyde en çok 2d düğüm bulunur. n düğümlü tam ikili ağacın yüksekliği h = ⌊log₂ n⌋.n = 7 → h = 2 · n = 1000 → h = 9
Neden önemli?Yeni öğe her zaman "son düzeyde en soldaki boş yere" gelir. Bu konum dizide tam olarak indeks n'dir.

İkili Heap

Heap mi, Değil mi?

1089357
(a)
10893127
(b)
13254
(c)
108976
(d)

Her ağaç için karar verin: max-heap mi, min-heap mi, yoksa heap değil mi? Hangi özellik bozuluyor?

Cevapları göster
  1. Max-heap ✓ (tam ağaç, her ebeveyn ≥ çocukları).
  2. Heap değil: 12 > ebeveyni 8 → heap-sıra özelliği bozuk.
  3. Min-heap ✓ (tam ağaç, her ebeveyn ≤ çocukları).
  4. Heap değil: 8'in çocukları yokken 9'un çocukları var → tam ağaç değil.

İkili Heap

Dizi Gösterimi

  • Düğümler kökten başlayarak düzey düzey, soldan sağa (level order) diziye yazılır.
  • Tam ağaç olduğu için dizide boşluk kalmaz; işaretçi (referans) gerekmez.
90316223145546heap[]90316223145546

Düğümlerin yanındaki küçük sayılar dizideki indeksleridir. Bu sunumda indeksler 0'dan başlar; kök heap[0]'dadır.

İkili Heap

Ebeveyn ve Çocuk Hesaplamaları

90316223145546heap[]90316223145546
Çocuklarsol(i) = 2i + 1 · sağ(i) = 2i + 2i = 1 → 3 ve 4 · i = 2 → 5 ve 6
Ebeveynebeveyn(i) = ⌊(i − 1) / 2⌋i = 6 → 2 · i = 5 → 2 · i = 4 → 1
  • Java'da tam sayı bölmesi zaten aşağı yuvarlar: (i - 1) / 2. Çocuk yoksa 2i + 1 ≥ n olur.
  • 1 tabanlı alternatif (orijinal sunum): heap[0] boş bırakılır; çocuklar 2k, 2k + 1; ebeveyn ⌊k/2⌋. İkisi eşdeğerdir, biri seçilip tutarlı kullanılmalıdır.

Ekleme ve Silme

Öğe Ekleme: Up-Heap (yüzdür, swim)

  1. Yeni öğe ağacın ilk boş konumuna (son düzeyde en soldaki boş yer = heap[n]) eklenir. Ağaç tam kalır.
  2. Heap-sıra özelliği bozulmuş olabilir: yeni öğe ebeveyninden büyükse (max-heap) yer değiştirilir.
  3. Öğe köke ulaşana ya da ebeveyni kendisinden büyük/eşit olana kadar yukarı taşınır.
MaliyetEn çok h = ⌊log₂ n⌋ yer değiştirme → O(log n).
Neden doğru?Yer değiştirmede aşağı inen ebeveyn, zaten diğer çocuğundan büyüktü.
Adlarıup-heap, bubble-up, sift-up, swim; orijinal kodda yuzdur.

Ekleme ve Silme

Up-Heap Örneği: ekle(10), ekle(8)

90316223145546heap[]90316223145546max-heapn = 7

Başlangıç max-heap: her ebeveyn ≥ çocukları. Dizi düzey düzey, soldan sağa tutulur.

90316223145546107heap[]90316223145546107ekle(10)n = 8

ekle(10): 10, ilk boş konuma (indeks 7) eklenir. Ebeveyni: (7−1)/2 = 3 → 2.

90316210314554627heap[]90316210314554627ekle(10)n = 8

10 > 2 → yer değiştir (indeks 7 ↔ 3).

90101623314554627heap[]90101623314554627ekle(10)n = 8

10 > 3 → yer değiştir (indeks 3 ↔ 1).

10091623314554627heap[]10091623314554627ekle(10)n = 8

10 > 9 → yer değiştir (indeks 1 ↔ 0). Kök → dur.

1009162331455462788heap[]1009162331455462788ekle(8)n = 9

ekle(8): 8, ilk boş konuma (indeks 8) eklenir. Ebeveyni: (8−1)/2 = 3 → 3.

1009162831455462738heap[]1009162831455462738ekle(8)n = 9

8 > 3 → yer değiştir (indeks 8 ↔ 3). Yeni ebeveyn 9 (indeks 1) ≥ 8 → dur.

Ekleme ve Silme

Boş Heap'e Art Arda Ekleme: 4, 5, 2, 6, 1, 3

40heap[]40123ekle(4)n = 1 · kapasite = 4

ekle(4): heap boş; 4 köke (indeks 0) yerleşir.

4051heap[]405123ekle(5)n = 2 · kapasite = 4

ekle(5): 5, ilk boş konuma (indeks 1) eklenir. Ebeveyni: (1−1)/2 = 0 → 4.

5041heap[]504123ekle(5)n = 2 · kapasite = 4

5 > 4 → yer değiştir (indeks 1 ↔ 0). Kök → dur.

504122heap[]5041223ekle(2)n = 3 · kapasite = 4

ekle(2): 2, ilk boş konuma (indeks 2) eklenir. Ebeveyni: (2−1)/2 = 0 → 5. 2 ≤ 5 → yer değiştirme yok.

50412263heap[]50412263ekle(6)n = 4 · kapasite = 4

ekle(6): 6, ilk boş konuma (indeks 3) eklenir. Ebeveyni: (3−1)/2 = 1 → 4.

50612243heap[]50612243ekle(6)n = 4 · kapasite = 4

6 > 4 → yer değiştir (indeks 3 ↔ 1).

60512243heap[]60512243ekle(6)n = 4 · kapasite = 4

6 > 5 → yer değiştir (indeks 1 ↔ 0). Kök → dur.

6051224314heap[]6051224314567ekle(1)n = 5 · kapasite = 8

Dizi dolu → buyut: kapasite 4 → 8. ekle(1): 1, ilk boş konuma (indeks 4) eklenir. Ebeveyni: (4−1)/2 = 1 → 5. 1 ≤ 5 → yer değiştirme yok.

605122431435heap[]60512243143567ekle(3)n = 6 · kapasite = 8

ekle(3): 3, ilk boş konuma (indeks 5) eklenir. Ebeveyni: (5−1)/2 = 2 → 2.

605132431425heap[]60513243142567ekle(3)n = 6 · kapasite = 8

3 > 2 → yer değiştir (indeks 5 ↔ 2). Yeni ebeveyn 6 (indeks 0) ≥ 3 → dur.

Ekleme ve Silme

Max-Heap'e Ekleme: Java Kodu

public class MaxHeap {
    private int[] heap = new int[4];
    private int n = 0;             // eleman sayısı

    public void ekle(int x) {
        if (n == heap.length) buyut(2 * heap.length);
        heap[n] = x;                   // ilk boş konum
        n++;
        yuzdur(n - 1);
    }

    private void yuzdur(int k) {   // up-heap
        while (k > 0 && heap[(k - 1) / 2] < heap[k]) {
            yerDegistir(k, (k - 1) / 2);
            k = (k - 1) / 2;
        }
    }
buyutDizi dolunca kapasite iki katına çıkar (amortize O(1)).
yerDegistirheap[a] ↔ heap[b] takası.
DurmaKökte ya da ebeveyn ≥ öğe olunca.

Ekleme ve Silme

En Büyüğü Çıkarma: Down-Heap (batır, sink)

  1. Kökteki öğe (en büyük) saklanır; döndürülecek değer budur.
  2. Ağacın son öğesi (heap[n − 1]) köke taşınır, n bir azalır. Ağaç tam kalır.
  3. Kök artık küçük bir değer taşıyabilir: büyük olan çocukla yer değiştirilir.
  4. Öğe bir yaprağa ulaşana ya da her iki çocuğundan büyük/eşit olana kadar aşağı taşınır.
Neden büyük çocuk?Küçük çocuk yukarı çıksaydı, diğer (büyük) çocuktan küçük bir ebeveyn olurdu. Min-heap'te ise küçük çocuk seçilir.
MaliyetHer düzeyde 2 karşılaştırma, en çok h düzey → O(log n).

Ekleme ve Silme

Down-Heap Örneği: silMax()

90316223145546heap[]90316223145546silMax()n = 7

silMax(): max = heap[0] = 9 (kök); döndürülecek değer.

40316223145596heap[]40316223145596silMax()n = 6

Kök ile son öğe yer değiştirir (0 ↔ 6); n = 6, 9 heap'in dışında. Yeni kök 4 özelliği bozabilir → down-heap.

60314223145596heap[]60314223145596silMax()n = 6

Çocuklar: 3 ve 6 → büyük olan 6. 4 < 6 → yer değiştir (0 ↔ 2).

60315223144596heap[]60315223144596silMax()n = 6

Tek çocuk 5; 4 < 5 → yer değiştir (2 ↔ 5). İndeks 5 yaprak → dur.

Ekleme ve Silme

Art Arda İki silMax()

1009162231455460738heap[]1009162231455460738silMax() #1n = 9

silMax() #1: max = heap[0] = 10 (kök); döndürülecek değer.

3091622314554607108heap[]3091622314554607108silMax() #1n = 8

Kök ile son öğe yer değiştirir (0 ↔ 8); n = 8, 10 heap'in dışında. Yeni kök 3 özelliği bozabilir → down-heap.

9031622314554607108heap[]9031622314554607108silMax() #1n = 8

Çocuklar: 9 ve 6 → büyük olan 9. 3 < 9 → yer değiştir (0 ↔ 1). 3 ≥ yeni çocukları 2 ve 1 → dur.

9031622314554607heap[]9031622314554607silMax() #2n = 8

silMax() #2: max = heap[0] = 9 (kök); döndürülecek değer.

0031622314554697heap[]0031622314554697silMax() #2n = 7

Kök ile son öğe yer değiştirir (0 ↔ 7); n = 7, 9 heap'in dışında. Yeni kök 0 özelliği bozabilir → down-heap.

6031022314554697heap[]6031022314554697silMax() #2n = 7

Çocuklar: 3 ve 6 → büyük olan 6. 0 < 6 → yer değiştir (0 ↔ 2).

6031522314054697heap[]6031522314054697silMax() #2n = 7

Çocuklar: 5 ve 4 → büyük olan 5. 0 < 5 → yer değiştir (2 ↔ 5). İndeks 5 yaprak → dur.

Ekleme ve Silme

En Büyüğü Çıkarma: Java Kodu

public int silMax() {
    if (n == 0) throw new NoSuchElementException();
    int max = heap[0];
    yerDegistir(0, n - 1);           // son öğe köke
    n--;
    batir(0);
    if (n > 0 && n == heap.length / 4)   // ¼ dolu
        kucult(heap.length / 2);
    return max;
}
private void batir(int k) {        // down-heap
    while (2 * k + 1 < n) {          // sol çocuk var mı?
        int j = 2 * k + 1;
        if (j + 1 < n && heap[j] < heap[j + 1]) j++;
        if (heap[k] >= heap[j]) break;
        yerDegistir(k, j);
        k = j;
    }
}
Boş heapÖnce kontrol edilir: istisna fırlatılır.
kucult¼ dolu kalınca kapasite yarıya iner.
TakasMax dizinin sonunda kalır → heap sort bunu kullanır.

Ekleme ve Silme

Min-Heap: insert(1) ve removeMin()

20513293648546heap[]20513293648546min-heapn = 7

Başlangıç min-heap: her ebeveyn ≤ çocukları; en küçük öğe (2) kökte.

2051329364854617heap[]2051329364854617insert(1)n = 8

insert(1): 1, ilk boş konuma (indeks 7) eklenir. Ebeveyni: (7−1)/2 = 3 → 9.

2051321364854697heap[]2051321364854697insert(1)n = 8

1 < 9 → yer değiştir (indeks 7 ↔ 3).

2011325364854697heap[]2011325364854697insert(1)n = 8

1 < 5 → yer değiştir (indeks 3 ↔ 1).

1021325364854697heap[]1021325364854697insert(1)n = 8

1 < 2 → yer değiştir (indeks 1 ↔ 0). Kök → dur.

1021325364854697heap[]1021325364854697removeMin()n = 8

removeMin(): min = heap[0] = 1 (kök); döndürülecek değer.

9021325364854617heap[]9021325364854617removeMin()n = 7

Kök ile son öğe yer değiştirir (0 ↔ 7); n = 7, 1 heap'in dışında. Yeni kök 9 özelliği bozabilir → down-heap.

2091325364854617heap[]2091325364854617removeMin()n = 7

Çocuklar: 2 ve 3 → küçük olan 2. 9 > 2 → yer değiştir (0 ↔ 1).

2051329364854617heap[]2051329364854617removeMin()n = 7

Çocuklar: 5 ve 6 → küçük olan 5. 9 > 5 → yer değiştir (1 ↔ 3). İndeks 3 yaprak → dur.

Ekleme ve Silme

Heap İşlemlerinin Maliyeti

İşlemMaliyetNeden?
size, isEmptyO(1)n sayacı tutulur
max / min (peek)O(1)Öğe hep heap[0]'dadır
ekle (insert)O(log n)*Up-heap: yapraktan köke tek yol
silMax (removeMin)O(log n)*Down-heap: kökten yaprağa tek yol
Rastgele öğeyi aramaO(n)Heap sıralı değildir; arama için uygun değil

* Dizi büyütme/küçültme dahil amortize maliyet. Yükseklik ⌊log₂ n⌋: n = 10⁶ öğede en çok 19 yer değiştirme.

Heap Oluşturma ve Heap Sort

n Öğeden Heap Oluşturma

Yol 1: n kez ekle

  • Her ekleme up-heap yapar: O(log n).
  • Toplam O(n log n).
  • Öğeler tek tek geliyorsa (çevrim içi) tek seçenektir.

Yol 2: aşağıdan yukarıya

  • Tüm öğeler baştan elimizdeyse diziyi olduğu gibi al.
  • Son iç düğümden (⌊n/2⌋ − 1) köke doğru her düğüme down-heap uygula.
  • Toplam O(n).
for (int i = n / 2 - 1; i >= 0; i--)   // son iç düğümden köke
    batir(i);                            // alt ağaçları heap olan i'yi batır

Heap Oluşturma ve Heap Sort

Aşağıdan Yukarıya Heap Oluşturma

40113223164951061478879heap[]40113223164951061478879heap oluşturn = 10

Sıradan bir dizi (heap değil). Yapraklar (indeks 5…9) zaten heap. Son iç düğüm 10/2 − 1 = 4'ten köke doğru her düğüme down-heap.

40113223164951061478879heap[]40113223164951061478879heap oluşturn = 10

i = 4: 16 (indeks 4) ≥ çocuku 7 → dur.

40113214316495106278879heap[]40113214316495106278879heap oluşturn = 10

i = 3: Çocuklar: 14 ve 8 → büyük olan 14. 2 < 14 → yer değiştir (3 ↔ 7). İndeks 7 yaprak → dur.

40111021431649536278879heap[]40111021431649536278879heap oluşturn = 10

i = 2: Çocuklar: 9 ve 10 → büyük olan 10. 3 < 10 → yer değiştir (2 ↔ 6). İndeks 6 yaprak → dur.

40161102143149536278879heap[]40161102143149536278879heap oluşturn = 10

i = 1: Çocuklar: 14 ve 16 → büyük olan 16. 1 < 16 → yer değiştir (1 ↔ 4).

40161102143749536278819heap[]40161102143749536278819heap oluşturn = 10

i = 1 (devam): Tek çocuk 7; 1 < 7 → yer değiştir (4 ↔ 9). İndeks 9 yaprak → dur.

16041102143749536278819heap[]16041102143749536278819heap oluşturn = 10

i = 0: Çocuklar: 16 ve 10 → büyük olan 16. 4 < 16 → yer değiştir (0 ↔ 1).

16014110243749536278819heap[]16014110243749536278819heap oluşturn = 10

i = 0 (devam): Çocuklar: 14 ve 7 → büyük olan 14. 4 < 14 → yer değiştir (1 ↔ 3).

16014110283749536274819heap[]16014110283749536274819heap oluşturn = 10

i = 0 (devam): Çocuklar: 2 ve 8 → büyük olan 8. 4 < 8 → yer değiştir (3 ↔ 8). İndeks 8 yaprak → dur. Sonuç: max-heap.

Heap Oluşturma ve Heap Sort

Aşağıdan Yukarıya Oluşturma Neden O(n)?

Düğümün yüksekliğiDüğümEn çok takasToplam
0 (yapraklar)800
1414
2224
3 (kök)133
n = 1511
  • Düğümlerin yarısı yapraktır ve hiç iş yapmaz; çok iş yapan (yüksek) düğüm sayısı azdır.
  • Genel olarak: Σh (n / 2h+1) · h ≤ n → O(n).
  • n kez eklemede ise çok sayıdaki derin düğüm uzun yol yürür: aynı ağaçta en kötü 0 + 2·1 + 4·2 + 8·3 = 34 takas.
Down-heap'in maliyeti düğümün yüksekliğine, up-heap'in maliyeti derinliğine bağlıdır. Düğümlerin çoğu aşağıdadır.

Heap Oluşturma ve Heap Sort

Heap Sort (Öbek Sıralaması)

Aşama 1: heap oluşturDizi aşağıdan yukarıya max-heap'e çevrilir. O(n)
Aşama 2: n − 1 kez silMaxKök (en büyük) dizinin sonundaki öğeyle takas edilir, heap bir küçülür, kök için down-heap. O(n log n)
  • Dizinin sonunda sıralı kısım büyür, başında heap küçülür; ek dizi gerekmez (yerinde, O(1) ek bellek).
  • En kötü durumda bile O(n log n): hızlı sıralamanın (quick sort) O(n²) kötü durumu yoktur.
  • Kararlı değildir (stable değil): eşit anahtarların göreli sırası değişebilir.
  • Max-heap artan sıralama, min-heap azalan sıralama üretir.

Heap Oluşturma ve Heap Sort

Heap Sort Örneği

605132431425heap[]605132431425heap sortn = 6

Aşama 1 bitti: dizi max-heap. Aşama 2: kökü (en büyük) sona al, heap'i küçült, down-heap.

205132431465heap[]205132431465heap sortn = 5

Kök 6 ile indeks 5'deki 2 yer değiştirir; 6 yerine oturdu, heap boyutu = 5.

502132431465heap[]502132431465heap sortn = 5

Çocuklar: 5 ve 3 → büyük olan 5. 2 < 5 → yer değiştir (0 ↔ 1).

504132231465heap[]504132231465heap sortn = 5

Çocuklar: 4 ve 1 → büyük olan 4. 2 < 4 → yer değiştir (1 ↔ 3). İndeks 3 yaprak → dur.

104132235465heap[]104132235465heap sortn = 4

Kök 5 ile indeks 4'deki 1 yer değiştirir; 5 yerine oturdu, heap boyutu = 4.

401132235465heap[]401132235465heap sortn = 4

Çocuklar: 4 ve 3 → büyük olan 4. 1 < 4 → yer değiştir (0 ↔ 1).

402132135465heap[]402132135465heap sortn = 4

Tek çocuk 2; 1 < 2 → yer değiştir (1 ↔ 3). İndeks 3 yaprak → dur.

102132435465heap[]102132435465heap sortn = 3

Kök 4 ile indeks 3'deki 1 yer değiştirir; 4 yerine oturdu, heap boyutu = 3.

302112435465heap[]302112435465heap sortn = 3

Çocuklar: 2 ve 3 → büyük olan 3. 1 < 3 → yer değiştir (0 ↔ 2). İndeks 2 yaprak → dur.

102132435465heap[]102132435465heap sortn = 2

Kök 3 ile indeks 2'deki 1 yer değiştirir; 3 yerine oturdu, heap boyutu = 2.

201132435465heap[]201132435465heap sortn = 2

Tek çocuk 2; 1 < 2 → yer değiştir (0 ↔ 1). İndeks 1 yaprak → dur.

102132435465heap[]102132435465heap sortn = 1

Kök 2 ile indeks 1'deki 1 yer değiştirir; 2 yerine oturdu, heap boyutu = 1. Dizi sıralı: [1, 2, 3, 4, 5, 6].

Heap Oluşturma ve Heap Sort

Heap Sort: Java Kodu

public static void heapSort(int[] a) {
    int n = a.length;
    for (int i = n / 2 - 1; i >= 0; i--) // 1) oluştur
        batir(a, i, n);
    for (int son = n - 1; son > 0; son--) { // 2) sırala
        yerDegistir(a, 0, son);   // en büyük sona
        batir(a, 0, son);         // heap boyutu = son
    }
}
static void batir(int[] a, int k, int n) {
    while (2 * k + 1 < n) {
        int j = 2 * k + 1;
        if (j + 1 < n && a[j] < a[j + 1]) j++;
        if (a[k] >= a[j]) break;
        yerDegistir(a, k, j);
        k = j;
    }
}
Aynı batirMaxHeap sınıfındakiyle aynı; yalnızca dizi ve heap boyutu parametre olarak geçer.
Deneme{4, 1, 3, 2, 16, 9, 10, 14, 8, 7}→ {1, 2, 3, 4, 7, 8, 9, 10, 14, 16}

Heap Oluşturma ve Heap Sort

Öncelikli Kuyrukla Sıralama

Genel fikir: tüm öğeleri öncelikli kuyruğa ekle, sonra n kez removeMin ile sırayla çıkar. Hangi sıralamayı elde ettiğimiz uygulamaya bağlıdır:

Uygulaman × insertn × removeMinOrtaya çıkan algoritma
Sırasız listeO(n)O(n²)Seçmeli sıralama (selection sort), O(n²)
Sıralı listeO(n²)O(n)Eklemeli sıralama (insertion sort), O(n²)
İkili heapO(n log n)O(n log n)Heap sort, O(n log n)
Aynı ADT, farklı veri yapısı: çalışma süresi O(n²)'den O(n log n)'e iner. ADT ile veri yapısı ayrımının (Bölüm 1) somut bir örneği.

Heap Oluşturma ve Heap Sort

Java'da Hazır Sınıf: PriorityQueue

PriorityQueue<Integer> pq = new PriorityQueue<>();
pq.offer(5); pq.offer(1); pq.offer(8);
pq.peek();   // 1  (min-heap, O(1))
pq.poll();   // 1  (O(log n))

// max-heap için ters karşılaştırıcı
PriorityQueue<Integer> maxPq =
    new PriorityQueue<>(Comparator.reverseOrder());

// hasta: öncelik küçük olan önce
PriorityQueue<Hasta> acil = new PriorityQueue<>(
    Comparator.comparingInt(h -> h.oncelik));
  • İçeride dizi tabanlı ikili min-heap kullanır.
  • offer/poll O(log n); peek, size O(1); remove(nesne) ve contains O(n).
  • Thread-safe değildir; çok iş parçacıklı kullanımda PriorityBlockingQueue tercih edilir.
  • Eşit öncelikte FIFO garantisi yoktur.

Özet

Özet

Öncelikli kuyrukinsert, min, removeMin. Öğeler öncelik sırasıyla çıkar.
Heap özelliğiTam ikili ağaç + ebeveyn ≥ çocuk (max) veya ≤ çocuk (min).
Dizi gösterimiçocuklar 2i+1, 2i+2 · ebeveyn ⌊(i−1)/2⌋
İşlemHeapNasıl?
peek (max/min)O(1)heap[0]
ekleO(log n)heap[n]'e koy, up-heap
silMax / removeMinO(log n)son öğeyi köke taşı, down-heap
heap oluşturmaO(n)⌊n/2⌋ − 1'den 0'a down-heap
heap sortO(n log n)oluştur + n − 1 kez kökü sona al

Özet

Etkileşimli Simülatörler

Bu bölümdeki işlemleri kendi değerlerinizle adım adım deneyin:

Heap simülatörüEkleme, en büyüğü/en küçüğü çıkarma; ağaç ve dizi görünümünde up-heap ve down-heap adımları.
Öncelikli kuyruk simülatörüÖncelikli öğeler ekleyip çıkararak ADT davranışını gözlemleyin.
Öncelikli görev çizelgeleyiciİşletim sistemi tarzı öncelikli çizelgeleme (Bölüm 5 ile bağlantı).
ÖneriÖrnek problemlerdeki dizileri simülatörde çalıştırıp cevaplarınızı karşılaştırın.

Özet

Örnek Problemler

  1. Boş bir max-heap'e sırasıyla 5, 12, 8, 3, 15, 10 ekleyin. Son dizi nedir?
  2. 1. sorudaki heap'e bir kez silMax() uygulayın. Dönen değer ve yeni dizi nedir?
  3. {3, 1, 6, 5, 2, 4} dizisini aşağıdan yukarıya yöntemle max-heap'e çevirin.
  4. 0 tabanlı dizide indeks 13'teki düğümün ebeveyni ve çocukları hangi indekslerdedir?
  5. {10, 7, 9, 8, 2, 5} bir max-heap midir? Değilse neden?
  6. Bir min-heap'teki en büyük öğeyi bulmanın maliyeti nedir?
Cevapları göster
  1. {15, 12, 10, 3, 5, 8}
  2. 15 döner; yeni dizi {12, 8, 10, 3, 5}.
  3. {6, 5, 4, 1, 2, 3}
  4. Ebeveyn ⌊(13 − 1)/2⌋ = 6; çocuklar 27 ve 28.
  5. Hayır: indeks 1'deki 7'nin çocuğu 8 (indeks 3) ondan büyük.
  6. O(n): en büyük öğe yapraklardan biridir ve yaklaşık n/2 yaprağın hepsine bakmak gerekir.

Ö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.
  • Oracle, Java SE 17 PriorityQueue API belgesi.

Son

Bölüm 8: Öncelikli Kuyruklar ve Heap
Sonraki bölüm: Eşlemeler ve Hash Tabloları
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.

← → veya boşluk ile gezinin · F: tam ekran · Home/End: ilk/son slayt