🔢 7.8: Counting Sort (Sayma Sıralaması)

Karşılaştırma Yapmadan O(n) Sıralama!

📌 Bu Bölümde Öğrenecekleriniz

🔢

Sayma Prensibi

Karşılaştırma yok!

O(n + k)

Linear zaman!

Stable

Sıra korunur

⚠️

Kısıtlı Kullanım

Sadece integer

🤔 Counting Sort Nedir?

Counting Sort, elemanları karşılaştırmadan sıralayan özel bir algoritmadır. Her elemanın kaç kez göründüğünü sayar ve bu bilgiyi kullanarak doğrudan doğru pozisyona yerleştirir.

💡 Neden Özel?

Karşılaştırma tabanlı sıralama algoritmaları (Quick, Merge, Heap) en iyi O(n log n) yapabilir. Bu matematiksel bir alt sınırdır!

Ama Counting Sort karşılaştırma yapmaz, bu yüzden bu sınırı aşabilir: O(n)!

⚠️ Önemli Kısıtlamalar

  • Sadece integer'lar için: Float, string vs. çalışmaz
  • Sınırlı aralık: k (max - min) çok büyükse verimsiz
  • O(k) ek alan: Değer aralığı kadar dizi gerekir
  • Negatif sayılar: Offset ile çözülebilir

🎬 Algoritma Adımları

Adım 1: Sayma Dizisi Oluştur

0'dan k'ya (max değer) kadar bir count dizisi oluştur, hepsini 0 ile başlat.

count = [0] * (k + 1)

Adım 2: Elemanları Say

Orijinal dizideki her eleman için, count dizisinde ilgili indeksi artır.

for x in arr: count[x] += 1

Adım 3: Kümülatif Toplam

Count dizisini kümülatif toplama dönüştür. Bu, her elemanın çıktıda nereye gideceğini söyler.

for i in range(1, len(count)): count[i] += count[i-1]

Adım 4: Çıktıyı Oluştur

Orijinal diziyi sondan başa tara (stability için), her elemanı doğru pozisyona yerleştir.

for x in reversed(arr):
  output[count[x] - 1] = x
  count[x] -= 1

👁️ Adım Adım Görsel Örnek

Diziyi sıralayalım: [4, 2, 2, 8, 3, 3, 1]

Adım 1-2: Sayma

Her elemanı say (max = 8, yani 0-8 arası count dizisi):

arr = [4, 2, 2, 8, 3, 3, 1]
index:  0  1  2  3  4  5  6  7  8
count: [0, 1, 2, 2, 1, 0, 0, 0, 1]
1→1 tane, 2→2 tane, 3→2 tane, 4→1 tane, 8→1 tane

Adım 3: Kümülatif Toplam

Her indeks, o değerin çıktıda "son pozisyonunu" gösterir:

index:   0  1  2  3  4  5  6  7  8
count: [0, 1, 3, 5, 6, 6, 6, 6, 7]
1→pos 1, 2→pos 3, 3→pos 5, 4→pos 6, 8→pos 7

Adım 4: Çıktıyı Oluştur (Sondan Başa)

arr[6]=1 → count[1]=1 → output[0]=1, count[1]=0
arr[5]=3 → count[3]=5 → output[4]=3, count[3]=4
arr[4]=3 → count[3]=4 → output[3]=3, count[3]=3
arr[3]=8 → count[8]=7 → output[6]=8, count[8]=6
arr[2]=2 → count[2]=3 → output[2]=2, count[2]=2
arr[1]=2 → count[2]=2 → output[1]=2, count[2]=1
arr[0]=4 → count[4]=6 → output[5]=4, count[4]=5
output = [1, 2, 2, 3, 3, 4, 8]

📊 Karmaşıklık Analizi

⏱️ Zaman

O(n + k)

n = eleman sayısı, k = aralık

💾 Alan

O(n + k)

count + output dizileri

🔄 Stable?

✅ Evet

Sondan başa tarama ile

🧮 O(n + k) Ne Demek?

  • n küçük, k büyük: Verimsiz! Örn: [1, 1000000] → O(1000000) alan
  • n büyük, k küçük: Harika! Örn: 1 milyon sınav notu (0-100) → O(n)
  • k = O(n) ise: Toplam O(n) → Quick Sort'tan hızlı!

💻 Python Implementasyonu

Counting Sort - Python
# ====================================
# COUNTING SORT ALGORİTMASI
# ====================================

def counting_sort(arr):
    """
    Counting Sort - Non-comparison sıralama
    
    Zaman: O(n + k) - n: eleman sayısı, k: değer aralığı
    Alan: O(n + k) - count ve output dizileri
    Stable: Evet (sondan başa tarama ile)
    
    Kısıtlamalar:
    - Sadece non-negative integer
    - k çok büyükse verimsiz
    """
    if len(arr) == 0:
        return arr
    
    # Adım 1: Min ve max bul
    min_val = min(arr)
    max_val = max(arr)
    k = max_val - min_val + 1  # Aralık
    
    print(f"📊 Dizi: {arr}")
    print(f"   Min: {min_val}, Max: {max_val}, Aralık (k): {k}")
    
    # Adım 2: Sayma dizisi oluştur
    count = [0] * k
    
    # Adım 3: Elemanları say
    for x in arr:
        count[x - min_val] += 1
    print(f"\n🔢 Sayma dizisi: {count}")
    
    # Adım 4: Kümülatif toplam
    for i in range(1, k):
        count[i] += count[i - 1]
    print(f"📈 Kümülatif: {count}")
    
    # Adım 5: Çıktı dizisi oluştur (sondan başa - stability için)
    output = [0] * len(arr)
    
    for i in range(len(arr) - 1, -1, -1):
        x = arr[i]
        idx = x - min_val
        output[count[idx] - 1] = x
        count[idx] -= 1
    
    print(f"\n✅ Sıralı: {output}")
    return output

# ============ TEST ============
print("=" * 50)
print("COUNTING SORT")
print("=" * 50)

dizi = [4, 2, 2, 8, 3, 3, 1]
counting_sort(dizi)

print("\n" + "=" * 50)
print("NEGATİF SAYILARLA TEST")
print("=" * 50)

dizi2 = [4, -2, 2, -8, 3, -3, 1]
counting_sort(dizi2)
Çıktı bekleniyor...

🎯 Ne Zaman Counting Sort Kullanılır?

✅ İdeal Durumlar

  • Sınav notları: 0-100 arası (k=101)
  • Yaş sıralama: 0-150 arası
  • Küçük integer'lar: k ≈ n olduğunda
  • Radix Sort alt rutini: Basamak sıralama
  • Stability gerektiğinde: Garantili stable

❌ Uygun Olmayan Durumlar

  • Float sayılar: Sonsuz değer aralığı
  • String'ler: Karakter karşılaştırması lazım
  • k >> n: [1, 1000000] gibi
  • Genel amaçlı: Quick/Merge daha pratik

🌍 Gerçek Hayat Kullanımları

🎓 Sınav Sonuçları

Milyonlarca öğrencinin sınav notunu (0-100) sırala. k=101, O(n) zaman!

📊 Histogram

Veri dağılımını göster. Counting Sort'un sayma adımı histogram verir!

🔢 Radix Sort

Her basamak için Counting Sort kullanır. 0-9 arası, k=10.

🎨 Pixel Sıralama

Görüntü işleme. RGB değerleri 0-255 arası, k=256.

📋 Bölüm Özeti

🔢 Algoritma

Say, kümüla, yerleştir

⏱️ Zaman

O(n + k)

💾 Alan

O(n + k)

✨ Özellik

Stable, sadece integer