📊 7.1: Sıralama Algoritmalarına Giriş

Veriyi Düzene Sokmak: Temel Kavramlar ve Karşılaştırma

📌 Bu Bölümde Öğrenecekleriniz

📊

Sıralama Nedir?

Temel konsept

⚖️

O(n²) vs O(n log n)

Karmaşıklık farkları

🔄

Stabilite

Neden önemli?

🎯

Doğru Seçim

Hangi algoritma?

🎯 Sıralama (Sorting) Nedir?

Sıralama, bir veri kümesindeki elemanları belirli bir düzene (artan veya azalan) göre yeniden organize etme işlemidir.

Sıralanmamış

64
25
12
22
11

Sıralanmış (Artan)

11
12
22
25
64

❓ Neden Sıralama Önemli?

🌟 Sıralama Neden Bu Kadar Önemli?

Sıralama, bilgisayar biliminin en çok çalışılan problemlerinden biridir. Neden?

🔧 Diğer Algoritmaların Ön Adımı

Birçok algoritma sıralı veri varsayar:

  • Binary Search: O(n) → O(log n)
  • Merge İşlemi: O(n) ile birleştirme
  • K'ıncı Eleman: Sıralı dizide O(1)
  • Closest Pair: Geometride sıralama şart

📈 CPU Zamanının %25-30'u

Endüstriyel araştırmalara göre:

  • Mainframe'lerde zamanın ~%25'i sıralamaya gider
  • Veritabanı query'lerinin çoğu sıralama içerir
  • Google, her gün trilyonlarca sıralama yapar
  • Küçük iyileştirmeler = büyük tasarruflar!

🎓 Algoritma Düşüncesi Öğretir

Sıralama algoritmaları temel teknikleri gösterir:

  • Divide & Conquer: Merge Sort, Quick Sort
  • Greedy: Selection Sort
  • Incremental: Insertion Sort
  • Non-comparison: Counting, Radix
💡 Mülakat Gerçeği: Tech şirketlerinde sıralama soruları çok yaygındır. "Bu problemi O(n log n)'de çöz" dendiğinde genellikle önce sıralama, sonra doğrusal işlem beklenir!

📚 Sıralama Algoritmaları Kategorileri

🔴 Basit Algoritmalar - O(n²)

Anlaması kolay, küçük veriler için uygun, büyük verilerde yavaş.

🫧 Bubble Sort

O(n²)

Yan yana elemanları karşılaştırıp takas eder. En büyük eleman "yukarı çıkar".

En iyi: O(n) (zaten sıralıysa)

📥 Insertion Sort

O(n²)

Her elemanı doğru yerine "sokar". Kart oyununda el düzenleme gibi.

En iyi: O(n) (neredeyse sıralıysa)

🎯 Selection Sort

O(n²)

En küçüğü bulup başa koyar. Her zaman O(n²).

Avantaj: Minimum takas sayısı

🟢 Verimli Algoritmalar - O(n log n)

Büyük veriler için optimize edilmiş, pratikte kullanılan algoritmalar.

🔀 Merge Sort

O(n log n)

Böl-birleştir stratejisi. Her zaman O(n log n) garantili.

Dezavantaj: O(n) ek bellek

⚡ Quick Sort

O(n log n)*

Pivot etrafında bölme. Pratikte en hızlı.

Dikkat: En kötü O(n²)

🏔️ Heap Sort

O(n log n)

Heap veri yapısı kullanır. In-place, garantili performans.

Dezavantaj: Cache-unfriendly

🟣 Özel Algoritmalar - O(n)

Belirli koşullarda çalışan lineer zamanlı algoritmalar.

🔢 Counting Sort

O(n + k)

Sayma tabanlı. Küçük aralıklı tamsayılar için ideal.

🪣 Bucket Sort

O(n + k)

Verileri kovalara dağıtır. Uniform dağılım için ideal.

🔤 Radix Sort

O(d × n)

Basamak basamak sıralar. Sabit uzunluklu sayılar için.

📊 Karmaşıklık Karşılaştırma Tablosu

Algoritma En İyi Ortalama En Kötü Alan Stable?
Bubble Sort O(n) O(n²) O(n²) O(1) ✅ Evet
Insertion Sort O(n) O(n²) O(n²) O(1) ✅ Evet
Selection Sort O(n²) O(n²) O(n²) O(1) ❌ Hayır
Merge Sort O(n log n) O(n log n) O(n log n) O(n) ✅ Evet
Quick Sort O(n log n) O(n log n) O(n²) O(log n) ❌ Hayır
Heap Sort O(n log n) O(n log n) O(n log n) O(1) ❌ Hayır

⚖️ Stabilite (Stability) Nedir?

Stabil bir sıralama algoritması, eşit değerli elemanların orijinal sırasını korur.

Orijinal Dizi

5🔴
3
5
2

✅ Stabil (Merge Sort)

2
3
5🔴
5

5🔴 hala 5♥'den önce

❌ Unstabil (Quick Sort)

2
3
5
5🔴

5'lerin sırası değişmiş olabilir

💡 Stabilite Ne Zaman Önemli?

Veritabanında önce isme göre, sonra tarihe göre sıralama yapıyorsanız, ikinci sıralama ilkini bozmamalı!

🎮 Görsel: Basit Sıralama Animasyonu

📚 Teknik Terimler Sözlüğü

Bu bölümde geçen bazı terimler size yabancı gelebilir. İşte açıklamaları:

Overhead (Ek Yük): Algoritmanın asıl işin dışında yaptığı ek işlemler. Örneğin recursive fonksiyon çağrıları, bellek ayırma, döngü başlatma gibi. Küçük verilerde bu ek işlemler, asıl sıralama işleminden daha uzun sürebilir!
Cache-friendly (Önbellek Dostu): CPU, RAM'den veri alırken sadece istenen veriyi değil, çevresindeki verileri de önbelleğe (cache) alır. Dizi elemanları yan yana olduğu için sırayla erişim hızlıdır. Quick Sort bunu iyi kullanır, Heap Sort ise parent-child atlamaları yüzünden cache'i kötü kullanır.
In-place (Yerinde): Algoritmanın ek bellek kullanmadan, mevcut dizi üzerinde çalışması. Merge Sort O(n) ek dizi ister, Quick Sort ve Heap Sort in-place çalışır.
Stabil (Kararlı): Eşit değerli elemanların orijinal sırasını koruyan algoritma. Veritabanında önce isme sonra tarihe göre sıralarken önemli.
Adaptive (Uyarlanabilir): Girdi verisinin durumuna göre performansı değişen algoritma. Insertion Sort neredeyse sıralı veride O(n), rastgelede O(n²).
Rastgele Erişim: Dizinin herhangi bir elemanına direkt erişebilme (arr[5] gibi). Linked List'te 5. elemana gitmek için baştan saymanız gerekir.

🤔 Hangi Algoritmayı Seçmeli?

Durum Önerilen Algoritma Sebep
Küçük veri (n < 50) Insertion Sort Basit, overhead yok (fonksiyon çağrısı, bellek ayırma gibi ek işlemler minimum)
Neredeyse sıralı veri Insertion Sort Adaptive algoritma - sıralı veride O(n)
Genel amaçlı (pratikte) Quick Sort Ortalamada en hızlı, cache-friendly (ardışık bellek erişimi)
Garantili O(n log n) gerekli Merge Sort Her zaman O(n log n), en kötü durumda bile
Bellek kısıtlı Heap Sort In-place, O(1) ek alan (orijinal dizi üzerinde çalışır)
Stabilite gerekli Merge Sort Stabil - eşit elemanların sırası korunur
Linked List sıralama Merge Sort Rastgele erişim gerektirmez - sıralı gezinme yeterli
Tamsayılar, küçük aralık Counting Sort O(n) - karşılaştırma yapmadan sayma ile sıralar

🐍 Python'da Sıralama

Python Kodu
# Python'un yerleşik sıralama fonksiyonları
# Timsort algoritması kullanır (Merge + Insertion Sort hibrit)

# 1. sorted() - Yeni liste döndürür
original = [64, 34, 25, 12, 22, 11, 90]
sirali = sorted(original)
print(f"Orijinal: {original}")
print(f"sorted(): {sirali}")

# 2. list.sort() - Listeyi yerinde sıralar
liste = [64, 34, 25, 12, 22, 11, 90]
liste.sort()
print(f"\n.sort(): {liste}")

# 3. Azalan sıra
azalan = sorted(original, reverse=True)
print(f"\nAzalan: {azalan}")

# 4. Özel anahtar ile sıralama
isimler = ["Zeynep", "Ali", "Mehmet", "Ayşe"]
isimler_sirali = sorted(isimler, key=len)  # Uzunluğa göre
print(f"\nUzunluğa göre: {isimler_sirali}")

# 5. Lambda ile karmaşık sıralama
# lambda x: x["not"] → Anonim fonksiyon, x alır, x["not"] döner
ogrenciler = [
    {"ad": "Ali", "not": 85},
    {"ad": "Ayşe", "not": 92},
    {"ad": "Mehmet", "not": 78}
]
nota_gore = sorted(ogrenciler, key=lambda x: x["not"], reverse=True)
print(f"\nNota göre:")
for o in nota_gore:
    print(f"  {o['ad']}: {o['not']}")
Çıktı bekleniyor...

🐍 Python Timsort Hakkında

Python'un sort() ve sorted() fonksiyonları Timsort algoritmasını kullanır:

  • Kim geliştirdi? Tim Peters, 2002'de Python için tasarladı
  • Nasıl çalışır? Merge Sort + Insertion Sort hibrit
  • Neden hibrit? Küçük parçalar için Insertion Sort daha hızlı (overhead yok), büyük parçalar Merge Sort ile birleştirilir
  • Karmaşıklık: En kötü O(n log n), en iyi O(n) (neredeyse sıralı veri)
  • Stabilite: ✅ Stabil
  • Kullanım: Python, Java, Android, Swift... birçok dil benimsedi

💡 İpucu: Kendi sıralama algoritmanızı yazmak yerine her zaman sorted() veya .sort() kullanın - çok optimize edilmiş!