Bölüm 8: Öncelikli Kuyruk
Klasik Soru · Heap
Soru 1: Max-Heap İşlemleri
Verilen max-heap'e sırasıyla ekle 85, ekle 95, sil, sil, ekle 50 uygulanıyor (sil = en büyüğü çıkar). Her adımdan sonra dizi gösterimini yazınız; son hâli çiziniz.
Dizi: [90, 70, 80, 40, 60, 75, 20, 10, 30]
Cevabı göster
| İşlem | Dizi |
|---|---|
| ekle 85 | 90 85 80 40 70 75 20 10 30 60 |
| ekle 95 | 95 90 80 40 85 75 20 10 30 60 70 |
| sil → 95 | 90 85 80 40 70 75 20 10 30 60 |
| sil → 90 | 85 70 80 40 60 75 20 10 30 |
| ekle 50 | 85 70 80 40 60 75 20 10 30 50 |
Ekleme: sona koy, ebeveynden büyükse yukarı taşı (up-heap). Silme: kökü al, son elemanı köke koy, büyük çocukla yer değiştirerek aşağı indir (down-heap). İkisi de O(log n).
Klasik Soru · Heap
Soru 2: Aşağıdan Yukarı Heap Oluşturma
[35, 12, 40, 5, 18, 7, 25, 3] dizisinden aşağıdan yukarı (bottom-up heapify) yöntemiyle min-heap oluşturunuz. Hangi indislerden başlanır? Elemanları tek tek eklemeye göre avantajı nedir?
Cevabı göster
Son iç düğüm indisi n/2 − 1 = 3. Sırasıyla indis 3, 2, 1, 0 için down-heap:
- i=3: 5 ↔ 3 → [35, 12, 40, 3, 18, 7, 25, 5]
- i=2: 40 ↔ 7 → [35, 12, 7, 3, 18, 40, 25, 5]
- i=1: 12 ↔ 3, sonra 12 ↔ 5 → [35, 3, 7, 5, 18, 40, 25, 12]
- i=0: 35, sırayla 3, 5 ve 12 ile yer değiştirir
Sonuç: [3, 5, 7, 12, 18, 40, 25, 35]
Aşağıdan yukarı oluşturma O(n); n kez ekleme O(n log n).
Klasik Soru · Heap
Soru 3: Heap Sort
[4, 10, 3, 5, 1] dizisini heap sort ile artan sırada sıralayınız. Önce max-heap oluşturup, her adımda kökü dizinin sonuna taşıyınız. Her adımdan sonraki diziyi yazınız. Karmaşıklık nedir? Kararlı (stable) mıdır?
Cevabı göster
| Adım | Dizi (| sonrası sıralı) |
|---|---|
| max-heap oluştur | 10 5 3 4 1 |
| 1. çıkarma | 5 4 3 1 | 10 |
| 2. çıkarma | 4 1 3 | 5 10 |
| 3. çıkarma | 3 1 | 4 5 10 |
| 4. çıkarma | 1 | 3 4 5 10 |
Sonuç: 1 3 4 5 10.
- Zaman: oluşturma O(n) + n × down-heap O(log n) = O(n log n) (en kötü durumda da).
- Ek bellek O(1): yerinde (in-place) sıralar.
- Kararlı değildir: eşit anahtarların sırası korunmayabilir.
Klasik Soru · Heap
Soru 4: PriorityQueue Çıktısı
Programın çıktısı nedir? System.out.println(pq) neden sıralı bir liste yazdırmaz?
var pq = new PriorityQueue<Integer>(); for (int x : new int[]{7, 2, 9, 4, 1}) pq.offer(x); System.out.print(pq.poll() + " "); System.out.print(pq.poll() + " "); pq.offer(3); System.out.print(pq.peek() + " "); System.out.print(pq.size()); var mx = new PriorityQueue<Integer>( Comparator.reverseOrder()); mx.addAll(List.of(7, 2, 9)); System.out.print(" " + mx.poll());
Cevabı göster
- Java'nın
PriorityQueue'su varsayılan olarak min-heaptir: poll → 1, poll → 2. - Kalan {4, 7, 9}; 3 eklenince en küçük 3: peek → 3, size → 4.
reverseOrder()ile max-heap: poll → 9.
Çıktı: 1 2 3 4 9
toString iç diziyi (heap sırasını) yazar; heap yalnızca ebeveyn ≤ çocuk koşulunu sağlar, tam sıralı değildir. Sıralı çıktı için tekrar tekrar poll gerekir.
Klasik Soru · Heap
Soru 5: En Büyük k Eleman
1 milyon elemanlı bir akıştan (stream) en büyük k = 10 elemanı bulmak istiyoruz. (a) Bütün veriyi sıralamak, (b) tüm veriyle max-heap kurup k kez silmek, (c) k boyutlu min-heap tutmak yöntemlerini zaman ve bellek açısından karşılaştırınız. Hangisi neden tercih edilir?
Cevabı göster
| Yöntem | Zaman | Bellek |
|---|---|---|
| (a) Sırala | O(n log n) | O(n) |
| (b) Max-heap + k silme | O(n + k log n) | O(n) |
| (c) k boyutlu min-heap | O(n log k) | O(k) |
(c) yönteminde her yeni eleman heap'in köküyle (k eleman içindeki en küçük) karşılaştırılır; daha büyükse kök çıkarılıp yeni eleman eklenir.
Akış verisinde tüm veri belleğe sığmayabilir; (c) yalnızca k eleman tuttuğu için tercih edilir. k küçükken log k ≈ sabittir.
Çoktan Seçmeli · Heap
Test 1
0 indisli max-heap dizisi [50, 30, 40, 10, 20, 35]. İndis 1'deki elemanın çocukları hangileridir?
Çocuklar 2i + 1 = 3 ve 2i + 2 = 4 → 10 ve 20.
Hangisi geçerli bir min-heap dizisidir?
Her ebeveyn ≤ çocukları olmalı. B'de 4 > 3 (indis 1 → 3), C'de 2 > 1, D'de 2 > 0 (indis 1 → 4).
Çoktan Seçmeli · Heap
Test 2
n elemanlı bir max-heap'te en küçük elemanı bulmanın karmaşıklığı nedir?
En küçük eleman yapraklardan biridir (≈ n/2 yaprak), hangisi olduğu bilinmez; hepsine bakılmalıdır.
n elemandan heap oluşturmak: tek tek ekleme ve aşağıdan yukarı (bottom-up) yöntemi sırasıyla:
Tek tek ekleme her biri O(log n). Bottom-up'ta düğümlerin çoğu alt seviyede olduğundan az iner; toplam O(n).
Adım Adım Çalıştırma · Heap
Max-Heap'e Ekleme (Up-Heap)
h = [50, 30, 40, 10, 20, 35], n = 6. ekle(60) çağrısını izleyin.
Önce tahmin edin: 60 kaç seviye yukarı çıkar?
60 dizinin sonuna (indis 6) yazılır.
i = 6, n = 7.
Ebeveyn (6−1)/2 = 2: h[2] = 40 < 60 → yukarı çık.
60 ile 40 yer değiştirir.
i = 2.
Ebeveyn 0: h[0] = 50 < 60 → yine yukarı.
60 köke çıkar.
i = 0 → döngü biter. 2 takas ≤ yükseklik: O(log n).
void ekle(int x) { h[n] = x; int i = n++; while (i > 0 && h[(i-1)/2] < h[i]) { int p = (i - 1) / 2; int t = h[p]; h[p] = h[i]; h[i] = t; i = p; } } // h = [50, 30, 40, 10, 20, 35], n = 6 // ekle(60);
Ucu Açık Soru · Heap
Acil Servis Sırası
- Acil serviste hastalar öncelik puanına göre çağrılıyor; aynı önceliktekiler geliş sırasına göre çağrılmalı. Heap kararlı (stable) değildir. Bunu nasıl sağlarsınız?
- Bekleyen bir hastanın durumu kötüleşir ve önceliği artarsa heap'te ne yapılmalıdır? Bu işlemi verimli yapmak için ek olarak neyi tutarsınız?
Örnek cevap ve değerlendirme ölçütleri
1. Her hastaya artan bir sıra numarası verilir ve karşılaştırma (öncelik, sıra no) çifti üzerinden yapılır: öncelik eşitse küçük sıra numarası önce gelir. Java'da bu bir Comparator ile yazılır: önce öncelik (büyük önce), eşitse sıra no (küçük önce).
2. Önceliği artan hastanın düğümü yukarı taşınır (increase-key + up-heap, O(log n)). Bunun için hastanın heap dizisindeki indisini bilmek gerekir: HashMap<Hasta, Integer> tutulur ve her takasta güncellenir (indeksli heap). Basit alternatif: hasta silinmiş işaretlenir, yeni öncelikle tekrar eklenir (lazy deletion); çıkarılan kayıt geçersizse atlanır.
Değerlendirme: kararlılık sorunu ve ikincil anahtar · öncelik değişiminde up-heap · konum tablosu ya da tembel silme · karmaşıklık.