Min-Heap ve Max-Heap oluşturma, heapify-up ile ekleme, heapify-down ile çıkarma, diziden O(n) build-heap, heap sort — adım adım görseller ve C kodu.
🗂️ Veri Yapıları📅 21 February 2026👁️ 2 görüntülenme
Heap Nedir?
Heap (yığın), iki özelliği aynı anda sağlayan özel bir ikili ağaçtır:
1. Tam İkili Ağaç (Complete Binary Tree): Son seviye hariç tüm seviyeler tamamen dolu; son seviye soldan sağa doldurulur. Bu yapı sayesinde heap bir dizi ile verimli temsil edilir.
2. Heap Kuralı (Heap Property): Her düğüm, çocuklarından küçük (Min-Heap) veya büyük (Max-Heap) olmalıdır. Bu kural her düğümde geçerlidir — kök her zaman en küçük (veya en büyük) elemanı tutar.
BST'den farklı olarak heap'te sol-sağ ayrımı yoktur — sadece ebeveyn-çocuk ilişkisi kuralı sağlar. Ayrıca heap'te arama O(n)'dir — heap arama için değil, min/max'a hızlı erişim için optimize edilmiştir.
Min-Heap vs Max-Heap
İki Heap Türü — Aynı Elemanlar, Farklı Kural
Min-Heap: ebeveyn ≤ çocuklar
Kök = minimum (5) → O(1) erişim
Max-Heap: ebeveyn ≥ çocuklar
Kök = maksimum (40) → O(1) erişim
Dizi Tabanlı Temsil
Heap'in en güçlü yönü: tam ikili ağaç olduğu için pointer'sız, düz bir dizi ile temsil edilir. Ebeveyn-çocuk ilişkisi basit indeks formülleriyle hesaplanır:
İndeks formülleri (0-tabanlı): Ebeveyn: (i - 1) / 2 Sol çocuk: 2*i + 1 Sağ çocuk: 2*i + 2
Ağaçta hareket etmek = dizide indeks hesaplamak. Pointer yok, malloc yok — cache-friendly.
Min-Heap: Ağaç ↔ Dizi Eşleştirmesi
5
[0]
10
[1]
15
[2]
20
[3]
30
[4]
25
[5]
40
[6]
Ör: [1]'in ebeveyni = (1-1)/2 = [0] ✓ | [2]'nin sol çocuğu = 2×2+1 = [5] ✓
Heap Yapısı (Dizi Tabanlı)
heap.c — yapı ve yardımcılar
#include<stdio.h>#include<stdlib.h>#definePARENT(i) (((i) - 1) / 2)
#defineLEFT(i) (2 * (i) + 1)
#defineRIGHT(i) (2 * (i) + 2)
typedefstruct {
int* data; // dinamik diziint size; // mevcut eleman sayısıint capacity; // dizi kapasitesi
} Heap;
Heap* heapOlustur(int kapasite) {
Heap* h = (Heap*)malloc(sizeof(Heap));
h->data = (int*)malloc(kapasite * sizeof(int));
h->size = 0;
h->capacity = kapasite;
return h;
}
voidswap(int* a, int* b) {
int t = *a; *a = *b; *b = t;
}
Pointer yok, dizi var: BST/AVL/RB ağaçlarında her düğüm malloc ile ayrı oluşturuluyordu. Heap'te ise tek bir ardışık dizi kullanılır — bu bellek lokasyonu açısından çok daha verimlidir. Ebeveyn/çocuk erişimi pointer takibi değil, basit aritmetik.
Eleman Ekleme — Heapify-Up
Yeni eleman dizinin sonuna eklenir (tam ikili ağaç yapısını korur), sonra heap kuralı sağlanana kadar ebeveynle yer değiştirerek yukarı tırmanır. Bu işleme "bubble-up" veya "sift-up" da denir.
Heapify-Up Algoritması (Min-Heap): 1. Elemanı dizinin sonuna ekle (index = size). 2. i = size olarak başla. 3. data[i] < data[PARENT(i)] ise → swap(i, PARENT(i)), i = PARENT(i). 4. Kural sağlanana veya köke ulaşılana kadar tekrarla.
Adım Adım — insert(3)
Mevcut Min-Heap: [5, 10, 15, 20, 30, 25, 40]. Şimdi 3 ekliyoruz.
voidheapifyUp(Heap* h, int i) {
while (i > 0 && h->data[i] < h->data[PARENT(i)]) {
swap(&h->data[i], &h->data[PARENT(i)]);
i = PARENT(i);
}
}
voidheapEkle(Heap* h, int deger) {
if (h->size >= h->capacity) {
h->capacity *= 2;
h->data = realloc(h->data, h->capacity * sizeof(int));
}
h->data[h->size] = deger; // sona ekleheapifyUp(h, h->size); // yukarı düzelt
h->size++;
}
Eleman Çıkarma — Heapify-Down
Min-Heap'ten minimum (kök) çıkarılır: kök ile son eleman yer değiştirilir, size azaltılır, sonra yeni kök heap kuralı sağlanana kadar aşağı batırılır. Her adımda daha küçük çocukla swap yapılır.
Heapify-Down Algoritması (Min-Heap): 1. Kökü (min) kaydet. Kök = son eleman. size--. 2. i = 0'dan başla. 3. En küçük çocuğu bul (sol mu sağ mı?). 4. data[i] > data[enKüçükÇocuk] ise → swap, i = enKüçükÇocuk. 5. Kural sağlanana veya yaprak olana kadar tekrarla.
voidheapifyDown(Heap* h, int i) {
int enKucuk = i;
int sol = LEFT(i);
int sag = RIGHT(i);
if (sol < h->size && h->data[sol] < h->data[enKucuk])
enKucuk = sol;
if (sag < h->size && h->data[sag] < h->data[enKucuk])
enKucuk = sag;
if (enKucuk != i) {
swap(&h->data[i], &h->data[enKucuk]);
heapifyDown(h, enKucuk); // alt ağaçta devam
}
}
intheapCikar(Heap* h) {
if (h->size <= 0) {
printf("Heap boş!\n");
return -1;
}
int min = h->data[0]; // kökü kaydet
h->data[0] = h->data[--h->size]; // son → kökheapifyDown(h, 0); // aşağı düzeltreturn min;
}
Heapify-Up vs Heapify-Down: İkisi de en fazla ağaç yüksekliği kadar adım atar → O(log n). Heapify-Up yapraktan köke, Heapify-Down kökten yaprağa çalışır. Ekleme = heapify-up, çıkarma = heapify-down.
Diziden Heap İnşa Etme (Build-Heap)
Elimizde rastgele sıralı bir dizi var. Bunu heap'e dönüştürmenin iki yolu:
Naif Yöntem — O(n log n)
Boş heap'e tek tek ekle. Her ekleme O(log n), n eleman → O(n log n).
Akıllı Yöntem — O(n) 🎯
Diziyi olduğu gibi ağaç say. Son yaprak-olmayan düğümden (n/2 - 1) geriye doğru her düğüme heapify-down uygula.
Neden O(n)? Yaprak düğümler (dizinin yarısı) zaten heap kuralını sağlar — hiç işlem gerekmez. Bir üst seviyedeki düğümler en fazla 1 adım, onların üstü 2 adım… Yalnızca kök log n adım atar. Toplam iş: n/4 × 1 + n/8 × 2 + n/16 × 3 + … = O(n). Bu, geometrik seri toplamının sonucudur.
Sonuç: [5, 10, 25, 20, 15, 30, 40] — geçerli Min-Heap ✓ | Sadece 4 swap ile inşa!
buildMinHeap() — O(n)
voidbuildMinHeap(Heap* h) {
// Son yaprak-olmayan düğümden geriye doğrufor (int i = h->size / 2 - 1; i >= 0; i--) {
heapifyDown(h, i);
}
}
Max-Heap
Max-Heap, Min-Heap'in sadece karşılaştırma yönü tersine çevrilmiş halidir: ebeveyn ≥ çocuklar. Kök her zaman en büyük elemanı tutar.
Max-Heap — karşılaştırma ters
voidmaxHeapifyDown(int arr[], int n, int i) {
int enBuyuk = i;
int sol = LEFT(i);
int sag = RIGHT(i);
if (sol < n && arr[sol] > arr[enBuyuk]) // > (büyük)
enBuyuk = sol;
if (sag < n && arr[sag] > arr[enBuyuk])
enBuyuk = sag;
if (enBuyuk != i) {
swap(&arr[i], &arr[enBuyuk]);
maxHeapifyDown(arr, n, enBuyuk);
}
}
voidbuildMaxHeap(int arr[], int n) {
for (int i = n / 2 - 1; i >= 0; i--)
maxHeapifyDown(arr, n, i);
}
Aynı Dizi → Max-Heap: [40, 20, 30, 10, 15, 5, 25]
Bu dizi zaten Max-Heap! 40≥20, 40≥30, 20≥10, 20≥15, 30≥5, 30≥25 ✓
Heap Sort
Heap Sort, Max-Heap yapısını kullanarak yerinde (in-place) sıralama yapar. Ek bellek gerektirmez. İki aşamadan oluşur:
Heap Sort Algoritması: Aşama 1: Diziyi Max-Heap'e dönüştür → buildMaxHeap() — O(n) Aşama 2: Tekrarla (n-1 kez): • Kök (max) ile son elemanı swap et → max sona gider (sıralı bölüme). • Heap boyutunu 1 azalt. • Yeni köke heapifyDown(0) uygula → O(log n).
Toplam: O(n) + O(n log n) = O(n log n)
Neden Max-Heap? Her adımda en büyük eleman köke gelir ve dizinin sonuna taşınır. Bu sayede sıralı bölüm dizinin sağından sola doğru büyür → artan sıralama elde edilir. Min-Heap kullanılsaydı azalan sıralama çıkardı.
| işareti heap ile sıralı bölümü ayırır. Sıralı bölüm sağdan sola büyür.
Heap Sort Kodu
heapSort() — yerinde, O(n log n)
voidheapSort(int arr[], int n) {
// Aşama 1: Max-Heap inşa et — O(n)buildMaxHeap(arr, n);
// Aşama 2: Tek tek çıkar — O(n log n)for (int i = n - 1; i > 0; i--) {
swap(&arr[0], &arr[i]); // max → sonamaxHeapifyDown(arr, i, 0); // küçülen heap'i düzelt
}
}
Sıralama Algoritmaları Karşılaştırması
Algoritma
En İyi
Ortalama
En Kötü
Alan
Kararlı?
Heap Sort
O(n log n)
O(n log n)
O(n log n)
O(1)
Hayır ✗
Quick Sort
O(n log n)
O(n log n)
O(n²)
O(log n)
Hayır ✗
Merge Sort
O(n log n)
O(n log n)
O(n log n)
O(n)
Evet ✓
Insertion Sort
O(n)
O(n²)
O(n²)
O(1)
Evet ✓
Heap Sort'un avantajı: En kötü durumda bile garanti O(n log n) — Quick Sort gibi O(n²) dejenere durumu yok. Ek bellek gerektirmez (O(1) alan). Dezavantajı: cache-unfriendly (dizide sıçramalar çok) ve kararsız (eşit elemanların sırası korunmaz).
Tam Demo Program
main() — heap operasyonları + heap sort
voidheapYazdir(Heap* h) {
for (int i = 0; i < h->size; i++)
printf("%d ", h->data[i]);
printf("\n");
}
intmain() {
printf("=== Min-Heap Demo ===\n\n");
// ── Tek tek ekleme ──Heap* h = heapOlustur(16);
int degerler[] = {40, 20, 30, 10, 15, 5, 25};
printf("--- Tek Tek Ekleme ---\n");
for (int i = 0; i < 7; i++) {
heapEkle(h, degerler[i]);
printf("insert(%2d) → ", degerler[i]);
heapYazdir(h);
}
// ── Min çıkarma ──printf("\n--- Min Çıkarma ---\n");
while (h->size > 0) {
int min = heapCikar(h);
printf("extractMin=%2d → ", min);
heapYazdir(h);
}
// ── Build-Heap + Heap Sort ──printf("\n--- Heap Sort ---\n");
int arr[] = {40, 20, 30, 10, 15, 5, 25};
int n = 7;
printf("Orijinal: ");
for (int i = 0; i < n; i++) printf("%d ", arr[i]);
printf("\n");
heapSort(arr, n);
printf("Sıralı: ");
for (int i = 0; i < n; i++) printf("%d ", arr[i]);
printf("\n");
free(h->data); free(h);
return0;
}
Doğru aracı seç: Arama önemliyse → BST/AVL. Sadece min/max'a hızlı erişim gerekiyorsa → Heap. Heap = uzmanlaşmış araç, BST = genel amaçlı araç.
Sonuç
Heap, tam ikili ağaç yapısını dizi temsili ile birleştirerek, pointer'sız ve cache-friendly bir veri yapısı sunar. Min-Heap'te kök her zaman minimum, Max-Heap'te her zaman maksimumdur — O(1) erişim. Ekleme (heapify-up) ve çıkarma (heapify-down) O(log n). Build-heap O(n) ile yerinde inşa edilir. Heap Sort ise bu mekanizmayı kullanarak garanti O(n log n) yerinde sıralama yapar.
Bölüm 6.5 özeti: Heap = tam ikili ağaç + heap kuralı (ebeveyn ≤ veya ≥ çocuklar). Dizi temsili: parent=(i-1)/2, left=2i+1, right=2i+2 — pointer yok. Ekleme: sona ekle + heapify-up → O(log n). Çıkarma: kökü al, son→kök, heapify-down → O(log n). Build-heap: son yaprak-olmayanından geriye heapifyDown → O(n). Heap Sort: buildMaxHeap + n×extractMax → O(n log n) garanti, O(1) ek alan. Min/Max erişim = O(1). Öncelik kuyruğu, Dijkstra, zamanlama, top-K, Huffman kodlama.