Bölüm 13: Öncelikli Kuyruk ve Heap

C ile Veri Yapıları ve Algoritmalar · Çalışma Soruları
Öncelikli kuyrukDizide tam ikili ağaçEklemeSilmeKarşılaştırmaHeapifyd-ary heap
Sercan KÜLCÜ

Çoktan Seçmeli · Öncelikli Kuyruk

Soru 1: Doğru Yapıyı Seçmek

Bir işletim sistemi, hazır işler arasından her seferinde en kısa sürecek işi çalıştırmak istiyor. İşler sık sık geliyor, “en kısayı ver” isteği de sık. Hangisi en uygundur?

B: Hem ekleme hem “en kısayı al” O(lg n) olur. A yanlış uca öncelik verir. Sıralı dizide yer ikili aramayla O(lg n)'de bulunsa da öğeleri kaydırmak O(n) sürer; sırasız listede ekleme O(1) ama en kısayı bulmak Θ(n)'dir.

Çoktan Seçmeli · Heap Yapısı

Soru 2: İndis Hesabı

50 öğeli, 1 tabanlı dizide tutulan bir heap'te (yigin[1..50]) 25. düğüm için hangisi doğrudur?

A: Ebeveyn 25 / 2 = 12 (tam sayı bölmesi). Çocuklar 2 · 25 = 50 ve 51 olurdu; 51 > n olduğu için yalnızca sol çocuk vardır. Tam ikili ağaçta en çok bir düğüm tek çocukludur: n çift ise n / 2 numaralı düğüm.

Çoktan Seçmeli · Heap Yapısı

Soru 3: Hangisi Maksimum Heap?

Aşağıdaki dizilerden (1 tabanlı, soldan sağa yigin[1..7]) hangisi bir maksimum heap'tir?

D: Her k ≥ 2 için yigin[k/2] ≥ yigin[k]: 90 ≥ 70, 80; 70 ≥ 20, 60; 80 ≥ 75, 10. A'da 4. indisteki 75, ebeveyni 70'ten büyük; B'de 5. indisteki 85, ebeveyni 80'den büyük; C'de 6. indisteki 85, ebeveyni 80'den büyük.

Çoktan Seçmeli · Heap Yapısı

Soru 4: Parantezsiz Makro

Makro parantezsiz tanımlanmıştır. Aşağıdaki kod ne yazdırır?

#define YIGIN_BOSMU(n) !n
int n = 5, k = 3;
printf("%d\n", YIGIN_BOSMU(n - k));

C: Önişlemci metni olduğu gibi yerleştirir: !n - k olur. ! önce uygulanır: !5 = 0, sonra 0 − 3 = −3. −3 sıfırdan farklı olduğu için koşulda “boş” sayılır, oysa 2 öğe vardır. Doğru tanım (!(n)) ile 0 yazılırdı.

Çıktı Sorusu · Ekleme

Soru 5: Art Arda Ekleme

Boş bir maksimum heap'e maksimum_yigin_ekle ile sırasıyla 12, 7, 19, 3, 15, 25 ekleniyor. Her eklemeden sonra dizi nedir? Toplam kaç kaydırma (yigin[i] = yigin[i / 2]) yapılır?

Cevabı göster
eklenenkaydırmayigin[1..n]
12012
7012 7
191 (12)19 7 12
3019 7 12 3
151 (7)19 15 12 3 7
252 (12, 19)25 15 19 3 7 12
3415275251126193

Toplam 4 kaydırma. 25 en kötü durumdur: köke kadar ⌊lg 6⌋ = 2 düzey çıkar.

Çoktan Seçmeli · Ekleme

Soru 6: Takas mı, Kaydırma mı?

Ekleme sırasında yeni öğe k düzey yukarı çıkıyor. Her adımda ebeveyniyle takas eden sürüm (takas başına 3 atama) ile sunumdaki kaydırma sürümü toplam kaç öğe ataması yapar?

C: Takasta her düzeyde geçici değişkenle 3 atama yapılır: 3k. Kaydırmada her düzeyde ebeveyn bir kez aşağı yazılır (k atama), yeni öğe en sonda bir kez yerine yazılır: k + 1.

Adım Adım Çalıştırma · Ekleme

Soru 7: ekle(55) Adım Adım

yigin[1..7] = 60 45 50 20 40 48 30 olan maksimum heap'e maksimum_yigin_ekle(55) uygulanıyor. Boşluk (?) nasıl ilerler, son dizi nedir? (Düğüm altındaki sayı indistir.)

204452405601486503307

Başlangıç heap'i.

?8204452405601486503307

Dolu değil; i = ++n = 8: tam ağacın ilk boş konumu. item henüz yazılmaz.

208?4452405601486503307

55 ≤ 20? Hayır → 20 aşağı kayar: yigin[8] = yigin[4].

208?4452405601486503307

i /= 2 → 4: boşluk bir düzey yukarıda.

208454?2405601486503307

55 ≤ 45? Hayır → 45 aşağı kayar: yigin[4] = yigin[2]; i = 2.

208454?2405601486503307

55 ≤ 60 → break: yer bulundu.

208454552405601486503307

yigin[2] = 55. Dizi: 60 55 50 45 40 48 30 20. 2 kaydırma + 1 yazma.

void maksimum_yigin_ekle(eleman item) {
  if (YIGIN_DOLUMU(n)) {
    yigin_dolu();
    return;
  }
  int i = ++n;
  while (i != 1) {
    if (item.x <= yigin[i / 2].x) break;
    yigin[i] = yigin[i / 2];
    i /= 2;
  }
  yigin[i] = item;
}

Hata Bulma · Ekleme

Soru 8: 0 Tabanlı Dizi, 1 Tabanlı Formül

Kök yigin[0]'da tutulan maksimum heap'e ekleme böyle yazılmıştır. Boş heap'e 1, 4, 5, 6, 2, 3, 7 eklenince dizi ne olur? Heap özelliği korunur mu? Hata nedir?

eleman yigin[16];  /* kök yigin[0] */
int n = 0;
void ekle(eleman item) {
  int i = n++;
  while (i != 0) {
    if (item.x <= yigin[i / 2].x) break;
    yigin[i] = yigin[i / 2];
    i /= 2;
  }
  yigin[i] = item;
}
Cevabı göster
eklenenyigin[0..n−1]
1, 4, 55 4 1
66 5 1 4
26 5 2 4 1
36 5 3 4 1 2
77 6 3 5 1 2 4

Son dizi heap değildir: 2. indisteki 3'ün çocuğu 6. indisteki 4'tür ve 3 < 4.

0 tabanlı dizide ebeveyn (i − 1) / 2'dir. i / 2 tek i'de doğru sonucu verir, çift i'de bir sonraki düğümü verir. 7, 6 → 3 → 1 → 0 yolunu izleyip 4'ü 3'ün altına iter; doğru yol 6 → 2 → 0'dır ve sonuç 7 5 6 1 2 3 4 olur.

Adım Adım Çalıştırma · Silme

Soru 9: al() Adım Adım

Önceki ekleme sorusunda oluşan 60 55 50 45 40 48 30 20 heap'ine maksimum_yigin_al(&e) uygulanıyor. Hangi öğeler yukarı alınır, son dizi nedir?

208454552405601486503307
454552405?1486503307

Kök (60) alınır; sondaki 20 çıkarılır, ona kökten yer aranır. n = 7.

454552405?1486503307

Çocuklar 55 ve 50: büyüğü j = 2. 20 ≥ 55? Hayır.

454?2405551486503307

55 yukarı alınır; boşluk 2. konuma iner.

?4452405551486503307

Çocuklar 45 ve 40: büyüğü 45; 20 ≥ 45? Hayır → 45 yukarı, boşluk 4. konuma.

204452405551486503307

j = 8 > n = 7: i yaprak. yigin[4] = 20. Dizi: 55 45 50 20 40 48 30; e = 60.

bool maksimum_yigin_al(eleman *cikan) {
  if (YIGIN_BOSMU(n)) return false;
  *cikan = yigin[1];
  eleman deger = yigin[n--];
  int i = 1, j = 2;
  while (j <= n) {
    if (j < n && yigin[j].x < yigin[j + 1].x)
      j++;
    if (deger.x >= yigin[j].x) break;
    yigin[i] = yigin[j];
    i = j; j *= 2;
  }
  yigin[i] = deger;
  return true;
}

Hata Bulma · Silme

Soru 10: Yanlış Çocuğu Seçmek

maksimum_yigin_al'da çocuk seçme satırındaki karşılaştırma ters yazılmıştır. 60 55 50 45 40 48 30 20 heap'ine bu yordam iki kez uygulanırsa ne olur?

if (j < n && yigin[j].x > yigin[j + 1].x)
  j++;          /* hatalı: küçük çocuk */
if (deger.x >= yigin[j].x) break;
yigin[i] = yigin[j];
i = j; j *= 2;
Cevabı göster
  • 1. çağrı: 60 doğru alınır. Kökte çocuklar 55 ve 50'dir; küçüğü (50) seçilir ve yukarı çıkar. Ardından 50'nin yerindeki çocuklardan küçüğü 30 seçilir. Dizi: 50 55 30 45 40 48 20.
  • Heap bozuldu: kökteki 50, çocuğu 55'ten küçük; 3. indisteki 30, çocuğu 48'den küçük.
  • 2. çağrı kökteki 50'yi döndürür; oysa en büyük 55'tir. Öncelikli kuyruk yanlış öğe verir.

Düzeltme: yigin[j].x < yigin[j + 1].x. Üç değerin (iki çocuk, deger) en büyüğü yukarı çıkmalıdır.

Çoktan Seçmeli · Silme

Soru 11: 4. İndisteki Öğe

Değerleri farklı, en az 8 öğeli bir maksimum heap'te 4. indisteki öğe için hangisi kesinlikle doğrudur?

A: Heap yalnızca ebeveyn ≥ çocuk ilişkisini garanti eder: yigin[4] < yigin[2] < yigin[1]. Kardeşler arasında sıra yoktur; 4. indisteki öğe ikinci büyük bile olmayabilir, yedinci büyük de olabilir. n ≥ 8 olduğu için 8. indis onun çocuğudur, yani yaprak da değildir.

Kod Yazma · Silme

Soru 12: Önceliği Azaltmak

Sunumdaki oncelik_artir'ın tersini yazın: void oncelik_azalt(int k, int yeni), maksimum heap'te k konumundaki öğenin önceliğini yeni (daha küçük) değerine indirip heap'i düzeltsin. 60 55 50 45 40 48 30 20 heap'inde oncelik_azalt(2, 10) sonrası dizi ne olur?

Cevabı göster
void oncelik_azalt(int k, int yeni) {
  eleman e = yigin[k];
  e.x = yeni;
  int j = 2 * k;
  while (j <= n) {          /* aşağı kaydır */
    if (j < n && yigin[j].x < yigin[j + 1].x)
      j++;                  /* büyük çocuk */
    if (e.x >= yigin[j].x) break;
    yigin[k] = yigin[j];    /* çocuğu yukarı al */
    k = j;  j *= 2;
  }
  yigin[k] = e;
}

Azalan öncelik ancak aşağıda ihlal yaratabilir; silmedeki aşağı kaydırma k'dan başlatılır: O(lg n). Örnekte 45 ve 20 birer düzey yukarı alınır, 10 8. konuma iner → 60 45 50 20 40 48 30 10.

Klasik Soru · Karşılaştırma

Soru 13: Sıralı Liste mi, Heap mi?

Bir öncelikli kuyrukta 1.048.576 (220) öğe var. Üzerinde 1000 ekleme ve 1000 “en büyüğü al” yapılacak. (a) Büyükten küçüğe sıralı bağlı listede, (b) maksimum heap'te en kötü durumda yaklaşık kaç adım sürer? (Bir karşılaştırma ya da kaydırma bir adım.)

Cevabı göster
1 ekleme1 almatoplam (1000 + 1000)
sıralı liste≈ 1.048.576 (yer aranır)1 (baştan)≈ 1,05 milyar
heap≤ 20 düzey≤ 20 düzey × 2 karş.≈ 20.000 + 40.000 = 60.000

lg 220 = 20 ve n en çok 1.049.576'ya çıkar: yükseklik değişmez. Heap yaklaşık 17.000 kat az iş yapar. Alma sayısı ekleme sayısına göre çok küçük olsaydı bile sıralı listede maliyeti eklemeler belirlerdi.

Çoktan Seçmeli · Karşılaştırma

Soru 14: Maliyet Tablosu

Öncelikli kuyruğu gerçekleyen yapılarla ilgili ifadelerden hangisi yanlıştır?

B yanlıştır: heap yalnızca ebeveyn–çocuk sırası tutar; aranan değer hangi alt ağaçta olabilir bilinmez, en kötü durumda bütün dizi taranır: O(n). Heap bir arama yapısı değildir. C'de en büyük dizinin sonundadır, yalnızca n azaltılır.

Adım Adım Çalıştırma · İleri Konular

Soru 15: yigin_kur Adım Adım

a[1..8] = 4 10 3 5 1 8 9 2 dizisine yigin_kur(a, 8) uygulanıyor. Her k için ne olur, son dizi nedir, kaç taşıma (a[i] = a[j]) yapılır?

28541021541863397

Henüz heap değil. Yapraklar (5–8) zaten tek öğelik heap'tir; k = n / 2 = 4'ten başlanır.

28541021541863397

k = 4: tek çocuk 2 (j = 8 = n, sağ çocuk yok). 5 ≥ 2 → yerinde kalır.

285410215418693?7

k = 3: çocuklar 8 ve 9 → büyüğü 9 (j = 7). 3 < 9 → 9 yukarı.

28541021541869337

j = 14 > n: a[7] = 3. 3 köklü alt ağaç heap oldu.

28541021541869337

k = 2: çocuklar 5 ve 1; 10 ≥ 5 → değişiklik yok.

285410215?1869337

k = 1: çocuklar 10 ve 9 → 10; 4 < 10 → 10 köke.

2854?215101869337

i = 2: çocuklar 5 ve 1 → 5; 4 < 5 → 5 yukarı.

28445215101869337

i = 4: tek çocuk 2; 4 ≥ 2 → a[4] = 4. Sonuç 10 5 9 4 1 8 3 2, 3 taşıma.

void yigin_kur(eleman a[], int n) {
  for (int k = n / 2; k >= 1; k--) {
    eleman deger = a[k];
    int i = k, j = 2 * k;
    while (j <= n) {
      if (j < n && a[j].x < a[j + 1].x)
        j++;
      if (deger.x >= a[j].x) break;
      a[i] = a[j];
      i = j; j *= 2;
    }
    a[i] = deger;
  }
}

Klasik Soru · İleri Konular

Soru 16: Artan Dizide Heapify

a[1..15] = 1, 2, …, 15 (artan) dizisine yigin_kur uygulanıyor. Kaç taşıma yapılır? Bu sayı, 15 düğümlü tam ağaç için “inebilecek toplam düzey” üst sınırıyla nasıl ilişkilidir? Dizi azalan sırada (15, 14, …, 1) verilseydi kaç taşıma olurdu?

Cevabı göster
  • Artan dizide her iç düğüm kendi alt ağacının en küçüğüdür ve yaprağa kadar iner: 4 düğüm (k = 4..7) 1'er, 2 düğüm (k = 2, 3) 2'şer, kök 3 düzey → 0 · 8 + 1 · 4 + 2 · 2 + 3 · 1 = 11 taşıma.
  • Bu, üst sınırın kendisidir: artan dizi yigin_kur için en kötü girdidir. Sınır Σ h · n / 2h+1 < n olduğundan kurma O(n)'dir.
  • Sonuç: 15 11 14 9 10 13 7 8 4 2 5 12 6 3 1.
  • Azalan dizi zaten bir maksimum heap'tir: her k'da ilk karşılaştırmada break → 0 taşıma.

Çoktan Seçmeli · İleri Konular

Soru 17: 4-ary Heap'te İndis

0 tabanlı dizide tutulan 4-ary (her düğümün 4 çocuğu olan) bir heap'te 10. indisteki düğümün ebeveyni ve çocukları hangi indislerdedir?

D: d-ary heap'te (0 tabanlı) ebeveyn (i − 1) / d = 9 / 4 = 2; çocuklar d · i + 1 … d · i + d = 41 … 44. Ağaç daha sığdır (yükseklik ≈ log₄ n), ekleme hızlanır; silmede ise her düzeyde 4 çocuk karşılaştırılır.

Son

Bölüm 13: Öncelikli Kuyruk ve Heap — Çalışma Soruları
Konu anlatımı: Öncelikli kuyruk ve heap sunumu · Ders notu · Terim sözlüğü
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.