Bölüm 2: Sıralama Algoritmaları

Algoritmalar
Kararlılık ve yerinde sıralamaKabarcıkEklemeliSeçimliShell BirleştirmeHızlıHeap sortSaymalı ve basamakTimsortKarşılaştırma
Sercan KÜLCÜ · Giresun Üniversitesi · Bilgisayar Mühendisliği

Giriş

Öğrenme Çıktıları

Kavramlar

Sıralamayı; zaman, ek bellek, kararlılık, yerinde çalışma ve karşılaştırmalı / karşılaştırmasız olma ölçütleriyle değerlendirmek.

Basit algoritmalar

Kabarcık, eklemeli, seçimli ve Shell sıralamasını bir dizi üzerinde adım adım izlemek ve Java ile yazmak.

Böl ve fethet, heap

Birleştirme sıralamasının, hızlı sıralamanın ve heap sort'un çalışmasını açıklamak; O(n log n) ve en kötü durum davranışlarını gerekçelendirmek.

Doğrusal zaman ve seçim

Karşılaştırma alt sınırını, saymalı ve basamak sıralamasını açıklamak; bir problem için uygun algoritmayı seçmek.

Giriş

Sıralama Algoritmaları

  • Alışveriş listelerinden sosyal medya gönderilerine kadar dijital dünyada sürekli veri ile karşılaşırız.
  • Verinin etkin kullanılabilmesi için düzenli tutulması gerekir.
  • Sıralama algoritmaları (sorting algorithms) bir listedeki öğeleri belirli bir ölçüte göre düzenler:
    • sayısal değer,
    • alfabetik sıra,
    • tarih …
  • Sıra artan (küçükten büyüğe) ya da azalan olabilir.
  • Biçimsel tanım: girdi ⟨a₁, a₂, …, aₙ⟩; çıktı, aynı sayıların a′₁ ≤ a′₂ ≤ … ≤ a′ₙ koşulunu sağlayan bir permütasyonu.
Sırasız72941sırala (artan)Sıralı12479
Sıralı veride ikili arama O(log n), tekrar bulma, birleştirme, ortanca ve en küçük/en büyük k öğe gibi işlemler çok kolaylaşır.

Giriş

Sıralama Algoritmalarının Çeşitleri

Farklı sıralama algoritmaları farklı çalışma prensiplerine sahiptir:

AlgoritmaTemel fikir
Kabarcık (Bubble Sort)Komşu öğeleri karşılaştırır, yanlış sıradaysa yer değiştirir.
Eklemeli (Insertion Sort)Sıradaki öğeyi sıralı kısımda doğru konuma yerleştirir.
Seçimli (Selection Sort)En küçük öğeyi bulup başa yerleştirir, sonra kalanları sıralar.
Shell (Shell Sort)Uzak öğelerle başlayan, aralığı küçülen eklemeli sıralama.
Birleştirme (Merge Sort)Diziyi yarıya böler, sıralar, sonra birleştirir.
Hızlı (Quick Sort)Pivot etrafında parçalar, iki parçayı özyinelemeli sıralar.
Heap (Heap Sort)Max-heap kurar, en büyüğü tekrar tekrar sona taşır.
Saymalı / Basamak (Counting / Radix)Karşılaştırma yapmaz; anahtarları sayar ya da basamak basamak dağıtır.
TimsortEklemeli ve birleştirme sıralamasının karması; Java ve Python'un nesne sıralaması.

Giriş

Bir Sıralama Algoritmasını Değerlendirmek

ZamanEn iyi, ortalama ve en kötü durumda karşılaştırma ve takas (taşıma) sayısı: Θ(n²), Θ(n log n), Θ(n + k) …
Ek bellekGirdinin dışında gereken alan. O(1) ek bellekle çalışan algoritma yerinde (in-place) sıralar.
KararlılıkEşit anahtarlı öğelerin göreli sırası korunuyorsa algoritma kararlıdır (stable).
Karşılaştırmalı mı?Yalnızca "a ≤ b?" sorusuyla çalışan algoritmalar en kötü durumda Ω(n log n) karşılaştırma yapar. Saymalı ve basamak sıralaması bu sınırın dışındadır.
UyarlanabilirlikNeredeyse sıralı girdide daha hızlı çalışan algoritma uyarlanabilirdir (adaptive): eklemeli, bayraklı kabarcık, Timsort.
Çevrim içiVeri geldikçe sıralayabilen algoritma çevrim içidir (online): eklemeli sıralama.

Giriş

Kararlılık (Stability): Örnek

Girdi(3, A)(1, B)(3, C)(2, D)(1, E)(3, F)3'ler: ACFKararlı (eklemeli)(1, B)(1, E)(2, D)(3, A)(3, C)(3, F)3'ler: ACFKararsız (seçimli)(1, B)(1, E)(2, D)(3, C)(3, A)(3, F)3'ler: CAF

Kayıtlar yalnızca sayıya (anahtar) göre sıralanır; harf, kaydın kimliğidir. Kararlı algoritmada anahtarı 3 olanlar girdideki gibi A, C, F sırasında kalır; seçimli sıralamanın uzun mesafeli takasları bu sırayı C, A, F yapar. (Bu girdi, simülatör laboratuvarındaki örnektir.)

Kararlılık, çok anahtarlı sıralamada önemlidir: öğrenciler önce ada, sonra (kararlı bir algoritmayla) bölüme göre sıralanırsa her bölümün içi alfabetik kalır. Basamak sıralaması da bu yüzden kararlı bir ara adım ister.

Kabarcık Sıralaması

Kabarcık Sıralaması (Bubble Sort)

  • Her turda dizideki büyük öğeler dizinin sonuna doğru kaydırılır; su içindeki kabarcık gibi yükselir.
  • Komşu öğeler ikili olarak karşılaştırılır.
  • Sol öğe büyükse yerleri değiştirilir (swap).
  • i. tur bittiğinde en büyük i öğe son yerlerindedir; bir sonraki tur bir öğe kısa olur.
  • Bir turda hiç takas olmazsa dizi sıralıdır → erken çıkış.
1. tur öncesi: komşu çiftler3152641. tur sonrası132546en büyük sonda

Kabarcık Sıralaması · Adım adım

Kabarcık Sıralaması Adım Adım: [3, 1, 5, 2, 6, 4]

Başlangıç301152236445

Dizi: [3, 1, 5, 2, 6, 4]. Her turda komşu çiftler soldan sağa karşılaştırılır; büyük olan sağa kayar.

1. Turjj+1301152236445

1. tur, j = 0: 3 > 1? Evet → yer değiştirilecek.

1. Turjj+1103152236445takas

Takas: dizi artık [1, 3, 5, 2, 6, 4].

1. Turjj+1103152236445

1. tur, j = 1: 3 > 5? Hayır → yerinde kalır.

1. Turjj+1103152236445

1. tur, j = 2: 5 > 2? Evet → yer değiştirilecek.

1. Turjj+1103122536445takas

Takas: dizi artık [1, 3, 2, 5, 6, 4].

1. Turjj+1103122536445

1. tur, j = 3: 5 > 6? Hayır → yerinde kalır.

1. Turjj+1103122536445

1. tur, j = 4: 6 > 4? Evet → yer değiştirilecek.

1. Turjj+1103122534465takas

Takas: dizi artık [1, 3, 2, 5, 4, 6].

1. Tur sonu103122534465

1. tur bitti: en büyük kalan öğe 6 son yerine (indis 5) yerleşti.

2. Turjj+1103122534465

2. tur, j = 0: 1 > 3? Hayır → yerinde kalır.

2. Turjj+1103122534465

2. tur, j = 1: 3 > 2? Evet → yer değiştirilecek.

2. Turjj+1102132534465takas

Takas: dizi artık [1, 2, 3, 5, 4, 6].

2. Turjj+1102132534465

2. tur, j = 2: 3 > 5? Hayır → yerinde kalır.

2. Turjj+1102132534465

2. tur, j = 3: 5 > 4? Evet → yer değiştirilecek.

2. Turjj+1102132435465takas

Takas: dizi artık [1, 2, 3, 4, 5, 6].

2. Tur sonu102132435465

2. tur bitti: en büyük kalan öğe 5 son yerine (indis 4) yerleşti.

3. Turjj+1102132435465

3. tur, j = 0: 1 > 2? Hayır → yerinde kalır.

3. Turjj+1102132435465

3. tur, j = 1: 2 > 3? Hayır → yerinde kalır.

3. Turjj+1102132435465

3. tur, j = 2: 3 > 4? Hayır → yerinde kalır.

3. Tur sonu102132435465

3. turda hiç takas olmadı → dizi sıralı; algoritma erken durur. Sonuç: [1, 2, 3, 4, 5, 6].

Kabarcık Sıralaması

Kabarcık Sıralaması: Java Kodu

boolean yerDegistiMi;
for(int i = 0; i < n - 1; i++) {
  yerDegistiMi = false;
  for(int j = 0; j < n - 1 - i; j++) {
    if(dizi[j] > dizi[j+1]) {
      int gecici = dizi[j];
      dizi[j] = dizi[j+1];
      dizi[j+1] = gecici;
      yerDegistiMi = true;
    }
  }
  if(yerDegistiMi == false) break;
}
  • Dış döngü (i): en fazla n − 1 tur.
  • İç döngü (j): sıralanmamış kısımdaki komşu çiftler; sondaki i öğe zaten yerinde olduğu için j < n − 1 − i.
  • Takas gecici değişkeniyle üç atamada yapılır.
  • yerDegistiMi bayrağı: tur boyunca hiç değiştirme yoksa dizi sıralıdır → break.
Koşul > olduğu (≥ değil) için eşit öğeler asla yer değiştirmez: kabarcık sıralaması kararlıdır.

Kabarcık Sıralaması · Kodu adım adım çalıştır

Kabarcık Sıralaması: Kodu İzle, dizi = [5, 1, 9, 2, 10]

dizi[]50119223104

n = 5. yerDegistiMi bayrağı tanımlanır.

dizi[]50119223104

Dış döngü i = 0: bayrak false yapılır.

dizi[]jj+150119223104

j = 0: dizi[0] = 5 > dizi[1] = 1? Evet.

dizi[]jj+110519223104yer değiştir

gecici = 5 ile yer değiştirilir; bayrak true.

dizi[]jj+110519223104

j = 1: dizi[1] = 5 > dizi[2] = 9? Hayır.

dizi[]jj+110519223104

j = 2: dizi[2] = 9 > dizi[3] = 2? Evet.

dizi[]jj+110512293104yer değiştir

gecici = 9 ile yer değiştirilir; bayrak true.

dizi[]jj+110512293104

j = 3: dizi[3] = 9 > dizi[4] = 10? Hayır.

dizi[]10512293104

Tur sonu: 10 yerine oturdu. Bayrak true → devam.

dizi[]10512293104

Dış döngü i = 1: bayrak false yapılır.

dizi[]jj+110512293104

j = 0: dizi[0] = 1 > dizi[1] = 5? Hayır.

dizi[]jj+110512293104

j = 1: dizi[1] = 5 > dizi[2] = 2? Evet.

dizi[]jj+110215293104yer değiştir

gecici = 5 ile yer değiştirilir; bayrak true.

dizi[]jj+110215293104

j = 2: dizi[2] = 5 > dizi[3] = 9? Hayır.

dizi[]10215293104

Tur sonu: 9 yerine oturdu. Bayrak true → devam.

dizi[]10215293104

Dış döngü i = 2: bayrak false yapılır.

dizi[]jj+110215293104

j = 0: dizi[0] = 1 > dizi[1] = 2? Hayır.

dizi[]jj+110215293104

j = 1: dizi[1] = 2 > dizi[2] = 5? Hayır.

dizi[]10215293104

Bu turda takas yok: break. Dizi sıralı: [1, 2, 5, 9, 10].

boolean yerDegistiMi;
for(int i = 0; i < n - 1; i++) {
  yerDegistiMi = false;
  for(int j = 0; j < n - 1 - i; j++) {
    if(dizi[j] > dizi[j+1]) {
      int gecici = dizi[j];
      dizi[j] = dizi[j+1];
      dizi[j+1] = gecici;
      yerDegistiMi = true;
    }
  }
  if(yerDegistiMi == false) break;
}

Kabarcık Sıralaması

Kabarcık Sıralaması: Analiz

DurumGirdiKarşılaştırmaTakasZaman
En iyisıralın − 1 (tek tur, bayrakla)0Θ(n)
Ortalamarastgele≈ n²/2≈ n²/4Θ(n²)
En kötüters sıralın(n − 1)/2n(n − 1)/2Θ(n²)
Artıları
  • Anlaşılması ve yazılması çok kolay.
  • Yerinde (O(1) ek bellek) ve kararlı.
  • Bayrakla sıralı girdiyi Θ(n)'de tanır.
Eksileri
  • Θ(n²): büyük dizilerde çok yavaş.
  • Çok fazla takas yapar (her ters çift = 1 takas).
  • Pratikte eklemeli sıralamadan hep yavaştır.

Ters çift (inversion): i < j iken dizi[i] > dizi[j]. Kabarcık ve eklemeli sıralama her adımda tam olarak bir ters çifti düzeltir; ters sıralı dizide n(n − 1)/2 ters çift vardır.

Eklemeli Sıralama

Eklemeli Sıralama (Insertion Sort)

  • Eldeki oyun kartlarını sıralamaya benzer: her yeni kart, eldeki sıralı kartların arasında doğru yere yerleştirilir.
  • Dizi iki parçaya ayrılır: sıralı kısım (solda) ve sırasız kısım.
  • Sırasız kısmın ilk öğesi alınır, sıralı kısımda doğru konumuna yerleştirilir.
  • Bunun için ondan büyük öğelerin bir sağa kaydırılması gerekir.
  • Değişmez (invariant): her dış adımın başında dizi[0..i−1] sıralıdır.
sıradaki103152236445← sıralısırasız →

Eklemeli Sıralama · Adım adım

Eklemeli Sıralama Adım Adım: [3, 1, 5, 2, 6, 4]

Başlangıç301152236445← sıralısırasız →

Dizi [3, 1, 5, 2, 6, 4]. İlk öğe tek başına sıralı kısımdır; geri kalanı sırasız.

i = 1i301152236445← sıralısırasız →gecici1

Sırasız kısmın ilk öğesi alınır: gecici = 1.

i = 1j303152236445← sıralısırasız →gecici1

3 > 1 → 3 bir sağa kaydırılır (indis 0 → 1).

i = 1j+1103152236445← sıralısırasız →

Dizinin başına gelindi → 1 indis 0'a yerleştirilir (1 kaydırma).

i = 2i103152236445← sıralısırasız →gecici5

Sırasız kısmın ilk öğesi alınır: gecici = 5.

i = 2j+1103152236445← sıralısırasız →

3 ≤ 5 → 5 indis 2'ye yerleştirilir (kaydırma gerekmedi).

i = 3i103152236445← sıralısırasız →gecici2

Sırasız kısmın ilk öğesi alınır: gecici = 2.

i = 3j103152536445← sıralısırasız →gecici2

5 > 2 → 5 bir sağa kaydırılır (indis 2 → 3).

i = 3j103132536445← sıralısırasız →gecici2

3 > 2 → 3 bir sağa kaydırılır (indis 1 → 2).

i = 3j+1102132536445← sıralısırasız →

1 ≤ 2 → 2 indis 1'e yerleştirilir (2 kaydırma).

i = 4i102132536445← sıralısırasız →gecici6

Sırasız kısmın ilk öğesi alınır: gecici = 6.

i = 4j+1102132536445← sıralısırasız →

5 ≤ 6 → 6 indis 4'e yerleştirilir (kaydırma gerekmedi).

i = 5i102132536445← sıralısırasız →gecici4

Sırasız kısmın ilk öğesi alınır: gecici = 4.

i = 5j102132536465← sıralıgecici4

6 > 4 → 6 bir sağa kaydırılır (indis 4 → 5).

i = 5j102132535465← sıralıgecici4

5 > 4 → 5 bir sağa kaydırılır (indis 3 → 4).

i = 5j+1102132435465← sıralı

3 ≤ 4 → 4 indis 3'e yerleştirilir (2 kaydırma). Dizi sıralı: [1, 2, 3, 4, 5, 6].

Eklemeli Sıralama

Eklemeli Sıralama: Java Kodu

for(int i = 1; i < n; i++) {
  int gecici = dizi[i];
  int j = i - 1;
  while(j >= 0 && dizi[j] > gecici) {
    dizi[j+1] = dizi[j];
    j = j - 1;
  }
  dizi[j+1] = gecici;
}
  • i = 1'den başlanır: tek öğeli dizi[0..0] zaten sıralıdır.
  • gecici: yerleştirilecek öğe (anahtar). Kaydırmalar onun hücresinin üzerine yazacağı için önce saklanır.
  • while: soldaki öğe büyük olduğu sürece bir sağa kaydırılır.
  • Döngü bitince boşalan yer j + 1'dir.
Takas (swap) değil kaydırma yapılır: her adımda 3 yerine 1 atama. Bu yüzden eklemeli sıralama kabarcıktan belirgin biçimde hızlıdır.

Eklemeli Sıralama · Kodu adım adım çalıştır

Eklemeli Sıralama: Kodu İzle, dizi = [5, 1, 9, 2, 10]

dizi[]50119223104← sıralısırasız →

n = 5. Sıralı kısım: yalnızca dizi[0].

dizi[]ij50119223104← sıralısırasız →gecici1

i = 1: gecici = dizi[1] = 1, j = 0.

dizi[]j50119223104← sıralısırasız →gecici1

j = 0 ≥ 0 ve dizi[0] = 5 > 1 → döngüye gir.

dizi[]j+150519223104← sıralısırasız →gecici1

dizi[1] = dizi[0] = 5 (sağa kaydır), j = −1.

dizi[]50519223104← sıralısırasız →gecici1

j = −1: döngü biter.

dizi[]j+110519223104← sıralısırasız →

dizi[0] = gecici = 1. Sıralı kısım: [1, 5].

dizi[]ij10519223104← sıralısırasız →gecici9

i = 2: gecici = dizi[2] = 9, j = 1.

dizi[]j10519223104← sıralısırasız →gecici9

dizi[1] = 5 ≤ 9: döngü biter.

dizi[]j+110519223104← sıralısırasız →

dizi[2] = gecici = 9. Sıralı kısım: [1, 5, 9].

dizi[]ij10519223104← sıralısırasız →gecici2

i = 3: gecici = dizi[3] = 2, j = 2.

dizi[]j10519223104← sıralısırasız →gecici2

j = 2 ≥ 0 ve dizi[2] = 9 > 2 → döngüye gir.

dizi[]j+110519293104← sıralısırasız →gecici2

dizi[3] = dizi[2] = 9 (sağa kaydır), j = 1.

dizi[]j10519293104← sıralısırasız →gecici2

j = 1 ≥ 0 ve dizi[1] = 5 > 2 → döngüye gir.

dizi[]j+110515293104← sıralısırasız →gecici2

dizi[2] = dizi[1] = 5 (sağa kaydır), j = 0.

dizi[]j10515293104← sıralısırasız →gecici2

dizi[0] = 1 ≤ 2: döngü biter.

dizi[]j+110215293104← sıralısırasız →

dizi[1] = gecici = 2. Sıralı kısım: [1, 2, 5, 9].

dizi[]ij10215293104← sıralısırasız →gecici10

i = 4: gecici = dizi[4] = 10, j = 3.

dizi[]j10215293104← sıralıgecici10

dizi[3] = 9 ≤ 10: döngü biter.

dizi[]j+110215293104← sıralı

dizi[4] = gecici = 10. Sıralı kısım: [1, 2, 5, 9, 10].

dizi[]10215293104

i = 5 < n değil → döngü biter. Sonuç: [1, 2, 5, 9, 10].

for(int i = 1; i < n; i++) {
  int gecici = dizi[i];
  int j = i - 1;
  while(j >= 0 && dizi[j] > gecici) {
    dizi[j+1] = dizi[j];
    j = j - 1;
  }
  dizi[j+1] = gecici;
}

Eklemeli Sıralama

Eklemeli Sıralama: Analiz

DurumGirdiKarşılaştırmaKaydırmaZaman
En iyisıralın − 10Θ(n)
Ortalamarastgele≈ n²/4≈ n²/4Θ(n²)
En kötüters sıralın(n − 1)/2n(n − 1)/2Θ(n²)
Artıları
  • Kararlı, yerinde, çevrim içi.
  • Uyarlanabilir: süre Θ(n + ters çift sayısı).
  • Küçük dizilerde (n ≲ 20–50) en hızlılardan.
Eksileri
  • Rastgele büyük dizilerde Θ(n²).
  • Bir öğe tek adımda yalnızca bir hücre ilerler; uzaktaki öğe çok kaydırma ister (→ Shell sıralaması).

Tüm girdiler için yalnızca O(n²) ve Ω(n) yazılabilir; tek bir Θ yoktur. Timsort ve birçok kütüphane, hızlı sıralamada ve birleştirme sıralamasında küçük alt dizileri eklemeli sıralamaya bırakır.

Seçimli Sıralama

Seçimli Sıralama (Selection Sort)

  • Dizi iki bölüme ayrılır: sıralı ve sırasız.
  • Her adımda:
    • Sırasız bölümden en küçük öğe bulunur.
    • Sırasız bölümün başındaki öğe ile yer değiştirilir.
    • Takasın ardından sıralı bölümün parçası olur.
  • Toplam n − 1 tur; her tur en fazla bir takas.
en küçük102152336445yer değiştir← sıralısırasız →

Seçimli Sıralama · Adım adım

Seçimli Sıralama Adım Adım: [3, 1, 5, 2, 6, 4]

Başlangıç301152236445sırasız →

Dizi [3, 1, 5, 2, 6, 4], uzunluk = 6. Başta sıralı kısım boştur.

1. Turen küçük301152236445sırasız →en küçük3

1. tur: sırasız kısmın ilk öğesi geçici en küçük kabul edilir: en küçük = 3.

1. Turen küçük301152236445sırasız →en küçük1

1 < en küçük (3)? Evet → en küçük = 1.

1. Turen küçükj301152236445sırasız →en küçük1

5 < en küçük (1)? Hayır.

1. Turen küçükj301152236445sırasız →en küçük1

2 < en küçük (1)? Hayır.

1. Turen küçükj301152236445sırasız →en küçük1

6 < en küçük (1)? Hayır.

1. Turen küçükj301152236445sırasız →en küçük1

4 < en küçük (1)? Hayır.

1. Tur103152236445yer değiştirsırasız →

En küçük (1) sırasız kısmın başıyla yer değiştirir → [1, 3, 5, 2, 6, 4]; sıralı kısım bir büyür.

2. Turen küçük103152236445← sıralısırasız →en küçük3

2. tur: sırasız kısmın ilk öğesi geçici en küçük kabul edilir: en küçük = 3.

2. Turen küçükj103152236445← sıralısırasız →en küçük3

5 < en küçük (3)? Hayır.

2. Turen küçük103152236445← sıralısırasız →en küçük2

2 < en küçük (3)? Evet → en küçük = 2.

2. Turen küçükj103152236445← sıralısırasız →en küçük2

6 < en küçük (2)? Hayır.

2. Turen küçükj103152236445← sıralısırasız →en küçük2

4 < en küçük (2)? Hayır.

2. Tur102152336445yer değiştir← sıralısırasız →

En küçük (2) sırasız kısmın başıyla yer değiştirir → [1, 2, 5, 3, 6, 4]; sıralı kısım bir büyür.

3. Turen küçük102152336445← sıralısırasız →en küçük5

3. tur: sırasız kısmın ilk öğesi geçici en küçük kabul edilir: en küçük = 5.

3. Turen küçük102152336445← sıralısırasız →en küçük3

3 < en küçük (5)? Evet → en küçük = 3.

3. Turen küçükj102152336445← sıralısırasız →en küçük3

6 < en küçük (3)? Hayır.

3. Turen küçükj102152336445← sıralısırasız →en küçük3

4 < en küçük (3)? Hayır.

3. Tur102132536445yer değiştir← sıralısırasız →

En küçük (3) sırasız kısmın başıyla yer değiştirir → [1, 2, 3, 5, 6, 4]; sıralı kısım bir büyür.

4. Turen küçük102132536445← sıralısırasız →en küçük5

4. tur: sırasız kısmın ilk öğesi geçici en küçük kabul edilir: en küçük = 5.

4. Turen küçükj102132536445← sıralısırasız →en küçük5

6 < en küçük (5)? Hayır.

4. Turen küçük102132536445← sıralısırasız →en küçük4

4 < en küçük (5)? Evet → en küçük = 4.

4. Tur102132436455yer değiştir← sıralısırasız →

En küçük (4) sırasız kısmın başıyla yer değiştirir → [1, 2, 3, 4, 6, 5]; sıralı kısım bir büyür.

5. Turen küçük102132436455← sıralısırasız →en küçük6

5. tur: sırasız kısmın ilk öğesi geçici en küçük kabul edilir: en küçük = 6.

5. Turen küçük102132436455← sıralısırasız →en küçük5

5 < en küçük (6)? Evet → en küçük = 5.

5. Tur102132435465yer değiştir← sıralısırasız →

En küçük (5) sırasız kısmın başıyla yer değiştirir → [1, 2, 3, 4, 5, 6]; sıralı kısım bir büyür.

Sonuç102132435465

5 tur sonunda son öğe kendiliğinden yerindedir. Sıralı dizi: [1, 2, 3, 4, 5, 6].

Seçimli Sıralama

Seçimli Sıralama: Java Kodu

public void sirala(int[] dizi) {
  int n = dizi.length;
  for(int i = 0; i < n - 1; i++) {
    int enKucuk = i;
    for(int j = i + 1; j < n; j++) {
      if(dizi[j] < dizi[enKucuk]) {
        enKucuk = j;
      }
    }
    int gecici = dizi[enKucuk];
    dizi[enKucuk] = dizi[i];
    dizi[i] = gecici;
  }
}
  • enKucuk en küçük öğenin indisini tutar (değerini değil): sonunda yer değiştirmek için indis gerekir.
  • İç döngü sırasız kısmın tamamını tarar; girdi sıralı olsa bile tarama kısalmaz.
  • Tur başına bir takas: toplam en fazla n − 1.
Yazma işleminin pahalı olduğu ortamlarda (ör. flash bellek) az sayıda takas seçimli sıralamanın tek gerçek avantajıdır.

Seçimli Sıralama · Kodu adım adım çalıştır

Seçimli Sıralama: Kodu İzle, dizi = [5, 1, 10, 2, 9]

dizi[]50111022394

n = dizi.length = 5.

dizi[]i, enKucuk50111022394sırasız →

i = 0: enKucuk = 0 (dizi[enKucuk] = 5).

dizi[]enKucukj50111022394sırasız →

j = 1: dizi[1] = 1 < dizi[enKucuk] = 5? Evet.

dizi[]enKucuk, j50111022394sırasız →

enKucuk = 1 (yeni en küçük: 1).

dizi[]enKucukj50111022394sırasız →

j = 2: dizi[2] = 10 < dizi[enKucuk] = 1? Hayır.

dizi[]enKucukj50111022394sırasız →

j = 3: dizi[3] = 2 < dizi[enKucuk] = 1? Hayır.

dizi[]enKucukj50111022394sırasız →

j = 4: dizi[4] = 9 < dizi[enKucuk] = 1? Hayır.

dizi[]ienKucuk10511022394yer değiştirsırasız →

j = 5 → iç döngü biter. gecici = 1; dizi[1] ↔ dizi[0] → [1, 5, 10, 2, 9].

dizi[]i, enKucuk10511022394← sıralısırasız →

i = 1: enKucuk = 1 (dizi[enKucuk] = 5).

dizi[]enKucukj10511022394← sıralısırasız →

j = 2: dizi[2] = 10 < dizi[enKucuk] = 5? Hayır.

dizi[]enKucukj10511022394← sıralısırasız →

j = 3: dizi[3] = 2 < dizi[enKucuk] = 5? Evet.

dizi[]enKucuk, j10511022394← sıralısırasız →

enKucuk = 3 (yeni en küçük: 2).

dizi[]enKucukj10511022394← sıralısırasız →

j = 4: dizi[4] = 9 < dizi[enKucuk] = 2? Hayır.

dizi[]ienKucuk10211025394yer değiştir← sıralısırasız →

j = 5 → iç döngü biter. gecici = 2; dizi[3] ↔ dizi[1] → [1, 2, 10, 5, 9].

dizi[]i, enKucuk10211025394← sıralısırasız →

i = 2: enKucuk = 2 (dizi[enKucuk] = 10).

dizi[]enKucukj10211025394← sıralısırasız →

j = 3: dizi[3] = 5 < dizi[enKucuk] = 10? Evet.

dizi[]enKucuk, j10211025394← sıralısırasız →

enKucuk = 3 (yeni en küçük: 5).

dizi[]enKucukj10211025394← sıralısırasız →

j = 4: dizi[4] = 9 < dizi[enKucuk] = 5? Hayır.

dizi[]ienKucuk10215210394yer değiştir← sıralısırasız →

j = 5 → iç döngü biter. gecici = 5; dizi[3] ↔ dizi[2] → [1, 2, 5, 10, 9].

dizi[]i, enKucuk10215210394← sıralısırasız →

i = 3: enKucuk = 3 (dizi[enKucuk] = 10).

dizi[]enKucukj10215210394← sıralısırasız →

j = 4: dizi[4] = 9 < dizi[enKucuk] = 10? Evet.

dizi[]enKucuk, j10215210394← sıralısırasız →

enKucuk = 4 (yeni en küçük: 9).

dizi[]ienKucuk10215293104yer değiştir← sıralısırasız →

j = 5 → iç döngü biter. gecici = 9; dizi[4] ↔ dizi[3] → [1, 2, 5, 9, 10].

dizi[]10215293104

i = 4 < n − 1 değil → biter. Sonuç: [1, 2, 5, 9, 10].

public void sirala(int[] dizi) {
  int n = dizi.length;
  for(int i = 0; i < n - 1; i++) {
    int enKucuk = i;
    for(int j = i + 1; j < n; j++) {
      if(dizi[j] < dizi[enKucuk]) {
        enKucuk = j;
      }
    }
    int gecici = dizi[enKucuk];
    dizi[enKucuk] = dizi[i];
    dizi[i] = gecici;
  }
}

Seçimli Sıralama

Seçimli Sıralama: Analiz

ÖlçüDeğer
Karşılaştırma(n − 1) + (n − 2) + … + 1 = n(n − 1)/2, her girdide
Takasen fazla n − 1
Zamanen iyi = ortalama = en kötü = Θ(n²)
Ek bellekO(1), yerinde
Kararlı mı?Hayır (uzun mesafeli takas)
Girdi2ₐ2ᵦ11. tur: takasÇıktı12ᵦ2ₐ

En küçük (1), baştaki 2ₐ ile yer değiştirir: 2ₐ, 2ᵦ'nin arkasına geçer.

Uyarlanabilir değildir: sıralı bir diziye de n(n − 1)/2 karşılaştırma harcar.

Basit Algoritmalar · Karşılaştırma

Kabarcık, Eklemeli, Seçimli: Aynı Girdide

Hücreler: karşılaştırma / takas (ya da kaydırma) sayısı, n = 6. Değerler kodlar çalıştırılarak sayılmıştır.

AlgoritmaTaşıma türü[3, 1, 5, 2, 6, 4]sıralı 1…6ters 6…1
Kabarcık (bayraklı)takas12 / 55 / 015 / 15
Eklemelikaydırma9 / 55 / 015 / 15
Seçimlitakas15 / 515 / 015 / 3
3152645 ters çift[3, 1, 5, 2, 6, 4]
  • Kabarcık ve eklemeli sıralamada taşıma sayısı = ters çift sayısı ([3, 1, 5, 2, 6, 4] için 5); bir takas 3, bir kaydırma 1 atamadır.
  • Seçimli sıralama girdiden bağımsız olarak hep n(n − 1)/2 = 15 karşılaştırma yapar ama en az takası o yapar.
  • Sıralı girdide bayraklı kabarcık ve eklemeli yalnızca n − 1 = 5 karşılaştırma yapar (uyarlanabilir).

Shell Sıralaması

Shell Sıralaması (Shell Sort)

  • D. Shell (1959): eklemeli sıralamanın genelleştirilmesi.
  • Önce birbirinden aralık (gap) uzaklıktaki öğeler eklemeli sıralanır; uzaktaki küçük öğeler tek hamlede büyük mesafe atlar.
  • Aralık küçültülür (n/2, n/4, …); son tur aralık = 1, yani sıradan eklemeli sıralama — ama dizi artık neredeyse sıralıdır.
  • Yerinde, kararsız; süre aralık dizisine bağlı: n/2 aralıklarıyla en kötü Θ(n²), Hibbard (2ᵏ − 1) ile O(n1,5).
void kabukSirala(int[] dizi) {
  int n = dizi.length;
  for (int aralik = n / 2; aralik > 0; aralik /= 2)
    for (int i = aralik; i < n; i++) {
      int gecici = dizi[i], j;
      for (j = i; j >= aralik && dizi[j - aralik] > gecici; j -= aralik)
        dizi[j] = dizi[j - aralik];
      dizi[j] = gecici;
    }
}

Shell Sıralaması · Adım adım

Shell Sıralaması Adım Adım: [6, 5, 3, 1, 8, 7, 2, 4]

Başlangıç6051321384752647

Dizi [6, 5, 3, 1, 8, 7, 2, 4], n = 8. Aralık dizisi: n/2 = 4, 2, … , 1.

aralik = 4: gruplar6051321384752647

aralik = 4: aralarında 4 indis olan öğeler aynı grupta (aynı renk): [6, 8], [5, 7], [3, 2], [1, 4].

aralik = 4: sonra6051221384753647

Her grup eklemeli sıralamayla sıralandı (1 kaydırma): [6, 8], [5, 7], [2, 3], [1, 4] → [6, 5, 2, 1, 8, 7, 3, 4].

aralik = 2: gruplar6051221384753647

aralik = 2: aralarında 2 indis olan öğeler aynı grupta (aynı renk): [6, 2, 8, 3], [5, 1, 7, 4].

aralik = 2: sonra2011324364558677

Her grup eklemeli sıralamayla sıralandı (6 kaydırma): [2, 3, 6, 8], [1, 4, 5, 7] → [2, 1, 3, 4, 6, 5, 8, 7].

aralik = 1: gruplar2011324364558677

aralik = 1: aralarında 1 indis olan öğeler aynı grupta (aynı renk): [2, 1, 3, 4, 6, 5, 8, 7].

aralik = 1: sonra1021324354657687

aralik = 1 sıradan eklemeli sıralamadır; dizi neredeyse sıralı olduğu için yalnızca 3 kaydırma gerekti. Sonuç: [1, 2, 3, 4, 5, 6, 7, 8].

Shell Sıralaması · Kodu adım adım çalıştır

Shell Sıralaması: Kodu İzle, dizi = [5, 2, 6, 1, 4, 3]

dizi502162134435●●○○◆◆aralik = 3: aynı işaretli öğeler bir grup

dizi = [5, 2, 6, 1, 4, 3], n = 6. İlk aralık n / 2 = 3: birbirinden 3 uzaktaki öğeler (0, 3), (1, 4), (2, 5) ayrı gruplar olarak eklemeli sıralanacak.

aralik = 3, i = 3, gecici = 1önce502162134435sonra126543j

i = 3: gecici = 1. dizi[0] = 5 > 1 → 3 indisine kayar. j = 0'da durulur; 1 oraya yazılır.

aralik = 3, i = 4, gecici = 4önce102162534435sonra126543j

i = 4: gecici = 4. dizi[1] = 2 ≤ 4: kaydırma yok, 4 yerinde kalır.

aralik = 3, i = 5, gecici = 3önce102162534435sonra123546j

i = 5: gecici = 3. dizi[2] = 6 > 3 → 5 indisine kayar. j = 2'de durulur; 3 oraya yazılır.

aralik = 1, i = 1, gecici = 2önce102132534465sonra123546j

aralik = 3 / 2 = 1: artık sıradan eklemeli sıralama. i = 1: gecici = 2. dizi[0] = 1 ≤ 2: kaydırma yok, 2 yerinde kalır.

aralik = 1, i = 2, gecici = 3önce102132534465sonra123546j

i = 2: gecici = 3. dizi[1] = 2 ≤ 3: kaydırma yok, 3 yerinde kalır.

aralik = 1, i = 3, gecici = 5önce102132534465sonra123546j

i = 3: gecici = 5. dizi[2] = 3 ≤ 5: kaydırma yok, 5 yerinde kalır.

aralik = 1, i = 4, gecici = 4önce102132534465sonra123456j

i = 4: gecici = 4. dizi[3] = 5 > 4 → 4 indisine kayar. dizi[2] = 3 ≤ 4, durulur; 4 oraya yazılır.

aralik = 1, i = 5, gecici = 6önce102132435465sonra123456j

i = 5: gecici = 6. dizi[4] = 5 ≤ 6: kaydırma yok, 6 yerinde kalır.

dizi102132435465

aralik = 1 / 2 = 0: döngü biter, dizi sıralı. Toplam yalnızca 3 kaydırma yapıldı; aralık 3 turu küçük öğeleri tek hamlede öne taşıdı.

void kabukSirala(int[] dizi) {
  int n = dizi.length;
  for (int aralik = n / 2; aralik > 0; aralik /= 2)
    for (int i = aralik; i < n; i++) {
      int gecici = dizi[i], j;
      for (j = i; j >= aralik && dizi[j - aralik] > gecici; j -= aralik)
        dizi[j] = dizi[j - aralik];
      dizi[j] = gecici;
    }
}

Birleştirme Sıralaması

Birleştirme Sıralaması (Merge Sort)

  • Böl ve fethet (divide and conquer) yaklaşımını kullanır.
  • 1945'te John von Neumann tarafından geliştirilmiştir.
  • En kötü durumda bile O(n log n).
  • Kararlıdır; birleştirme için ek bellek (O(n)) gerekir.
Nasıl çalışır?

1. Böl (divide): liste iki alt listeye bölünür; alt listeler tek öğe kalana kadar tekrar tekrar bölünür.

2. Fethet (conquer): her yarı aynı yöntemle (özyinelemeli) sıralanır.

3. Birleştir (combine): sıralı alt listeler, sıralı tek bir liste oluşana kadar birleştirilir.

3827433382743327383433273843bölsıralabirleştir
Tek öğeli liste tanım gereği sıralıdır; bu, özyinelemenin taban durumudur. Asıl iş birleştirme adımında yapılır.

Birleştirme Sıralaması

Örnek: [38, 27, 43, 3, 9, 82, 10]

Girdi382743398210Böl382743398210Böl382743398210Böl382743398210Birleştir273834398210Birleştir327384391082Birleştir391027384382

Yedi öğe: orta = ⌊(sol + sağ)/2⌋ olduğu için sol yarı bir öğe fazla alır ([38, 27, 43, 3] ve [9, 82, 10]).

Birleştirme Sıralaması · Adım adım

Merge Sort Adım Adım: [6, 5, 3, 1, 8, 7, 2, 4]

65318724

Dizi [6, 5, 3, 1, 8, 7, 2, 4]: önce tek öğe kalana kadar bölünür, sonra sıralı parçalar birleştirilir.

6531872465318724

Böl: [6, 5, 3, 1, 8, 7, 2, 4] → [6, 5, 3, 1] ve [8, 7, 2, 4].

65318724653187246531

Böl: [6, 5, 3, 1] → [6, 5] ve [3, 1].

6531872465318724653165

Böl: [6, 5] → [6] ve [5]. Tek öğeli parçalar zaten sıralıdır.

6531872465318724563165

Birleştir: [6] + [5] → [5, 6].

653187246531872456316531

Böl: [3, 1] → [3] ve [1]. Tek öğeli parçalar zaten sıralıdır.

653187246531872456136531

Birleştir: [3] + [1] → [1, 3].

653187241356872456136531

Birleştir: [5, 6] + [1, 3] → [1, 3, 5, 6].

6531872413568724561387246531

Böl: [8, 7, 2, 4] → [8, 7] ve [2, 4].

653187241356872456138724653187

Böl: [8, 7] → [8] ve [7]. Tek öğeli parçalar zaten sıralıdır.

653187241356872456137824653187

Birleştir: [8] + [7] → [7, 8].

65318724135687245613782465318724

Böl: [2, 4] → [2] ve [4]. Tek öğeli parçalar zaten sıralıdır.

65318724135687245613782465318724

Birleştir: [2] + [4] → [2, 4].

65318724135624785613782465318724

Birleştir: [7, 8] + [2, 4] → [2, 4, 7, 8].

12345678135624785613782465318724

Birleştir: [1, 3, 5, 6] + [2, 4, 7, 8] → [1, 2, 3, 4, 5, 6, 7, 8]. Dizi sıralandı.

Birleştirme Sıralaması

Merge Sort: Java Kodu

void birlestirmeliSirala(int[] dizi, int sol, int sag) {
  if (sol < sag) {
    int orta = sol + (sag - sol) / 2;
    birlestirmeliSirala(dizi, sol, orta);
    birlestirmeliSirala(dizi, orta + 1, sag);
    birlestir(dizi, sol, orta, sag);
  }
}
void birlestir(int[] A, int p, int q, int r) {
  int[] L = Arrays.copyOfRange(A, p, q + 1);
  int[] R = Arrays.copyOfRange(A, q + 1, r + 1);
  int i = 0, j = 0, k = p;
  while (i < L.length && j < R.length) {
    if (L[i] <= R[j]) A[k++] = L[i++];
    else              A[k++] = R[j++];
  }
  while (i < L.length) A[k++] = L[i++];
  while (j < R.length) A[k++] = R[j++];
}

sol + (sag − sol) / 2 yazımı, (sol + sag) / 2 toplamındaki int taşmasını önler.

Birleştirme Sıralaması · Kodu adım adım çalıştır

birlestir(): İki Sıralı Diziyi Birleştir

L1356iR2478jA01234567k

L = A[p..q] = [1, 3, 5, 6] ve R = A[q+1..r] = [2, 4, 7, 8] kopyalanır (ikisi de sıralı). i = j = 0, k = p = 0.

L1356iR2478jA101234567k

L[0] = 1 ≤ R[0] = 2 → A[0] = 1; i++, k++.

L1356iR2478jA1021234567k

L[1] = 3 > R[0] = 2 → A[1] = 2; j++, k++.

L1356iR2478jA10213234567k

L[1] = 3 ≤ R[1] = 4 → A[2] = 3; i++, k++.

L1356iR2478jA102132434567k

L[2] = 5 > R[1] = 4 → A[3] = 4; j++, k++.

L1356iR2478jA1021324354567k

L[2] = 5 ≤ R[2] = 7 → A[4] = 5; i++, k++.

L1356R2478jA10213243546567k

L[3] = 6 ≤ R[2] = 7 → A[5] = 6; i++, k++.

L1356R2478jA102132435465767k

L bitti (i = 4); kalan R öğeleri sırayla kopyalanır: A[6] = 7.

L1356R2478A1021324354657687

A[7] = 8. Birleştirme bitti: [1, 2, 3, 4, 5, 6, 7, 8] (8 öğe, en fazla 7 karşılaştırma).

void birlestir(int[] A, int p, int q, int r) {
  int[] L = Arrays.copyOfRange(A, p, q + 1);
  int[] R = Arrays.copyOfRange(A, q + 1, r + 1);
  int i = 0, j = 0, k = p;
  while (i < L.length && j < R.length) {
    if (L[i] <= R[j]) A[k++] = L[i++];
    else              A[k++] = R[j++];
  }
  while (i < L.length) A[k++] = L[i++];
  while (j < R.length) A[k++] = R[j++];
}

Birleştirme Sıralaması

Merge Sort: Analiz

Yineleme bağıntısı (recurrence):

T(n) = 2 T(n/2) + Θ(n)

  • Her düzeyde toplam birleştirme işi Θ(n).
  • Düzey sayısı log₂ n (n'yi 1'e kadar yarılamak).
  • Toplam: Θ(n log n) — en iyi = ortalama = en kötü.
  • Ek bellek Θ(n) (yardımcı diziler) + Θ(log n) özyineleme yığını.
  • L[i] <= R[j]: eşitlikte soldan alınır → kararlı.
nnn/2n/2nn/4n/4n/4n/4n⋮⋮11111111nΣ = n · log₂ nlog₂ n düzey
Ana teoremle: a = 2, b = 2, f(n) = Θ(n) = Θ(nlog₂ 2) → 2. durum → T(n) = Θ(n log n).

Hızlı Sıralama

Hızlı Sıralama (Quick Sort)

  • C. A. R. Hoare (1959). Yine böl ve fethet, ama işin çoğu bölmede yapılır.
  • Bir pivot öğe seçilir.
  • Dizi pivot etrafında iki parçaya bölünür (bölümleme, partitioning): solda ≤ x, sağda ≥ x.
  • İki alt parça özyinelemeli olarak sıralanır. Birleştirme adımına gerek yoktur.
≤ xx≥ xpivotsol parça → özyinelemeli sıralasağ parça → özyinelemeli sırala
Bölümlemeden sonra pivot kesin yerindedir: sıralı dizide de tam o indiste duracaktır.

Hızlı Sıralama

Bölümleme (Partitioning) Prosedürü

Lomuto: pivot = son öğe

parcala(A, p, q):
  pivot = A[q]        // pivot seç
  i = p - 1           // ≤ pivot bölgesinin sonu
  for j = p to q - 1:
    if A[j] <= pivot:
      i = i + 1
      takas(A[i], A[j])
  takas(A[i + 1], A[q])  // pivotu yerleştir
  return i + 1          // pivotun indisi

Aynı fikir: pivot = ilk öğe

PARCALA(A, p, q):
  x = A[p]            // pivot
  i = p
  for j = p + 1 to q:
    if A[j] <= x:
      i = i + 1
      takas(A[i], A[j])
  takas(A[p], A[i])
  return i

Değişmez (invariant): A[p..i] ≤ pivot, A[i+1..j−1] > pivot, A[j..] henüz incelenmedi. Tek geçiş: Θ(n) zaman, O(1) ek bellek.

Hızlı Sıralama · Adım adım

Parçalara Ayırma: [6, 10, 13, 5, 8, 3, 2, 11]

x = A[p] = 6ij6010113253843526117

Pivot x = A[p] = 6 (sarı). i = p; j, p + 1'den başlar. Mavi: ≤ x, kırmızı: > x, beyaz: henüz bakılmadı.

j = 1ij6010113253843526117

A[j] = 10 > 6 → yalnızca j ilerler; kırmızı bölge büyür.

j = 2ij6010113253843526117

A[j] = 13 > 6 → yalnızca j ilerler; kırmızı bölge büyür.

j = 3ij6051132103843526117takas

A[j] = 5 ≤ 6 → i = 1; A[i] ↔ A[j]: [6, 5, 13, 10, 8, 3, 2, 11]. Mavi bölge bir büyüdü.

j = 4ij6051132103843526117

A[j] = 8 > 6 → yalnızca j ilerler; kırmızı bölge büyür.

j = 5ij6051321038413526117takas

A[j] = 3 ≤ 6 → i = 2; A[i] ↔ A[j]: [6, 5, 3, 10, 8, 13, 2, 11]. Mavi bölge bir büyüdü.

j = 6ij6051322384135106117takas

A[j] = 2 ≤ 6 → i = 3; A[i] ↔ A[j]: [6, 5, 3, 2, 8, 13, 10, 11]. Mavi bölge bir büyüdü.

j = 7ij6051322384135106117

A[j] = 11 > 6 → yalnızca j ilerler; kırmızı bölge büyür.

Son: A[p] ↔ A[i]i2051326384135106117takas

Döngü bitti. Pivot, mavi bölgenin son öğesiyle yer değiştirir: [2, 5, 3, 6, 8, 13, 10, 11]. Pivot 6 artık kesin yerinde (indis 3); solu ≤ 6, sağı ≥ 6.

Hızlı Sıralama · Kodu adım adım çalıştır

parcala(): Kodu İzle, dizi = [2, 8, 7, 1, 3, 5, 6, 4]

dizi[]2081721334556647

pivot = dizi[ust] = 4; i = alt − 1 = −1 (≤ pivot bölgesi boş).

dizi[]j2081721334556647

j = 0: dizi[0] = 2 ≤ 4? Evet.

dizi[]i, j2081721334556647

i = 0; takas(dizi, 0, 0) → [2, 8, 7, 1, 3, 5, 6, 4] (kendisiyle).

dizi[]ij2081721334556647

j = 1: dizi[1] = 8 ≤ 4? Hayır → j ilerler.

dizi[]ij2081721334556647

j = 2: dizi[2] = 7 ≤ 4? Hayır → j ilerler.

dizi[]ij2081721334556647

j = 3: dizi[3] = 1 ≤ 4? Evet.

dizi[]ij2011728334556647takas

i = 1; takas(dizi, 1, 3) → [2, 1, 7, 8, 3, 5, 6, 4].

dizi[]ij2011728334556647

j = 4: dizi[4] = 3 ≤ 4? Evet.

dizi[]ij2011328374556647takas

i = 2; takas(dizi, 2, 4) → [2, 1, 3, 8, 7, 5, 6, 4].

dizi[]ij2011328374556647

j = 5: dizi[5] = 5 ≤ 4? Hayır → j ilerler.

dizi[]ij2011328374556647

j = 6: dizi[6] = 6 ≤ 4? Hayır → j ilerler.

dizi[]i2011324374556687takas

Döngü bitti. takas(dizi, i+1 = 3, ust = 7) → [2, 1, 3, 4, 7, 5, 6, 8].

dizi[]i2011324374556687

return 3: pivot 4 kesin yerinde; sol [0..2] ≤ 4, sağ [4..7] > 4.

int parcala(int[] dizi, int alt, int ust) {
  int pivot = dizi[ust];
  int i = alt - 1;
  for (int j = alt; j < ust; j++) {
    if (dizi[j] <= pivot) {
      i++;
      takas(dizi, i, j);
    }
  }
  takas(dizi, i + 1, ust);
  return i + 1;
}

Hızlı Sıralama

QuickSort: Özyinelemeli Yapı

HIZLI-SIRALA(A, p, r)
  if p < r
    q = PARCALA(A, p, r)
    HIZLI-SIRALA(A, p, q − 1)
    HIZLI-SIRALA(A, q + 1, r)

İlk çağrı: HIZLI-SIRALA(A, 1, n)
void hizliSirala(int[] dizi, int alt, int ust) {
  if (alt < ust) {
    int p = parcala(dizi, alt, ust);
    hizliSirala(dizi, alt, p - 1);
    hizliSirala(dizi, p + 1, ust);
  }
}
≤ pivot: alt … p − 1p> pivot: p + 1 … usthizliSirala(dizi, alt, p − 1)hizliSirala(dizi, p + 1, ust)yerinde
  • Pivot (indis q) iki özyinelemeli çağrının hiçbirine dahil edilmez: yerine oturmuştur.
  • Taban durumu: 0 ya da 1 öğeli alt dizi (p ≥ r) zaten sıralıdır.
  • Java sürümü 0-tabanlıdır: ilk çağrı hizliSirala(dizi, 0, n − 1).

Hızlı Sıralama · Adım adım

QuickSort Adım Adım: [6, 10, 13, 5, 8, 3, 2, 11]

HIZLI-SIRALA(A, 0, 7)6010113253843526117

Dizi [6, 10, 13, 5, 8, 3, 2, 11]. Her çağrı alt diziyi pivot = ilk öğe ile parçalar, sonra iki tarafı özyinelemeli sıralar.

HIZLI-SIRALA(A, 0, 7)q2051326384135106117

Derinlik 0: [6, 10, 13, 5, 8, 3, 2, 11] pivot 6 ile bölümlenir → pivot indis 3'e oturur; sonra [0..2] ve [4..7] sıralanır.

HIZLI-SIRALA(A, 0, 2)q2051326384135106117

Derinlik 1: [2, 5, 3] pivot 2 ile bölümlenir → pivot indis 0'a oturur; sonra [0..-1] ve [1..2] sıralanır.

HIZLI-SIRALA(A, 1, 2)q2031526384135106117

Derinlik 2: [5, 3] pivot 5 ile bölümlenir → pivot indis 2'ye oturur; sonra [1..1] ve [3..2] sıralanır.

HIZLI-SIRALA(A, 1, 1)q2031526384135106117

Derinlik 3: [1..1] tek öğeli (3) → zaten sıralı (p < r değil).

HIZLI-SIRALA(A, 4, 7)q2031526384135106117

Derinlik 1: [8, 13, 10, 11] pivot 8 ile bölümlenir → pivot indis 4'e oturur; sonra [4..3] ve [5..7] sıralanır.

HIZLI-SIRALA(A, 5, 7)q2031526384115106137

Derinlik 2: [13, 10, 11] pivot 13 ile bölümlenir → pivot indis 7'ye oturur; sonra [5..6] ve [8..7] sıralanır.

HIZLI-SIRALA(A, 5, 6)q2031526384105116137

Derinlik 3: [11, 10] pivot 11 ile bölümlenir → pivot indis 6'ya oturur; sonra [5..5] ve [7..6] sıralanır.

HIZLI-SIRALA(A, 5, 5)q2031526384105116137

Derinlik 4: [5..5] tek öğeli (10) → zaten sıralı (p < r değil).

Sonuç2031526384105116137

Tüm çağrılar bitti; birleştirme adımı yok, dizi yerinde sıralandı: [2, 3, 5, 6, 8, 10, 11, 13].

Hızlı Sıralama · Kodu adım adım çalıştır

hizliSirala: Çağrıları İzle, dizi = [5, 2, 8, 1, 9, 3]

201132539485dizi(0, 5)(0, 1)(3, 5)(0, -1)(1, 1)(3, 3)(5, 5)

hizliSirala(0, 5): alt < ust. parcala pivot = 3 (son öğe) ile böler: [2, 1] solda, [5, 9, 8] sağda; pivot p = 2 indisine oturur. Sonra satır 4: sol parça.

102132539485dizi(0, 5)(0, 1)(3, 5)(0, -1)(1, 1)(3, 3)(5, 5)

hizliSirala(0, 1): alt < ust. parcala pivot = 1 (son öğe) ile böler: [] solda, [2] sağda; pivot p = 0 indisine oturur.

102132539485dizi(0, 5)(0, 1)(3, 5)(0, -1)(1, 1)(3, 3)(5, 5)

hizliSirala(0, -1): alt > ust, boş parça → hemen döner (taban durum).

102132539485dizi(0, 5)(0, 1)(3, 5)(0, -1)(1, 1)(3, 3)(5, 5)

hizliSirala(1, 1): tek öğeli parça [2] zaten sıralı → döner. (0, 1) çağrısı biter; satır 5: (3, 5).

102132538495dizi(0, 5)(0, 1)(3, 5)(0, -1)(1, 1)(3, 3)(5, 5)

hizliSirala(3, 5): alt < ust. parcala pivot = 8 (son öğe) ile böler: [5] solda, [9] sağda; pivot p = 4 indisine oturur.

102132538495dizi(0, 5)(0, 1)(3, 5)(0, -1)(1, 1)(3, 3)(5, 5)

hizliSirala(3, 3): tek öğeli parça [5] zaten sıralı → döner.

102132538495dizi(0, 5)(0, 1)(3, 5)(0, -1)(1, 1)(3, 3)(5, 5)

hizliSirala(5, 5): tek öğeli parça [9] zaten sıralı → döner.

102132538495dizi(0, 5)(0, 1)(3, 5)(0, -1)(1, 1)(3, 3)(5, 5)

Tüm çağrılar döndü: dizi = [1, 2, 3, 5, 8, 9]. 3 parcala ve 4 taban çağrısı; pivotlar hiçbir alt çağrıya girmedi, her biri kendi yerine oturdu.

void hizliSirala(int[] dizi, int alt, int ust) {
  if (alt < ust) {
    int p = parcala(dizi, alt, ust);
    hizliSirala(dizi, alt, p - 1);
    hizliSirala(dizi, p + 1, ust);
  }
}

Hızlı Sıralama

QuickSort: Analiz ve Pivot Seçimi

DurumNe zaman?YinelemeZaman
En iyipivot her seferinde ortancaT(n) = 2T(n/2) + Θ(n)Θ(n log n)
Ortalamarastgele girdi / rastgele pivotbeklenen ≈ 1,39 n log₂ n karşılaştırmaΘ(n log n)
En kötüpivot hep en küçük/en büyük (ör. sıralı dizi + son öğe pivot)T(n) = T(n − 1) + Θ(n)Θ(n²)
Rastgele pivotPivotu rastgele seçmek kötü girdiyi olanaksız kılar; beklenen süre her girdide Θ(n log n).
Üçün ortancasıİlk, orta ve son öğenin ortancası pivot olur; sıralı girdide en kötü durumu önler.
Küçük parçalarn ≲ 16 olunca eklemeli sıralamaya geçmek ve küçük tarafa önce inmek (yığın O(log n)) pratikte hızlandırır.

Yerinde (O(log n) ortalama yığın), kararsız. Önbellek dostu olduğu için pratikte genellikle en hızlı karşılaştırmalı sıralamadır (Java Arrays.sort(int[]): çift pivotlu quicksort).

Heap Sort

Heap Sort

  • Heap veri yapısını kullanarak sıralar; ortalama ve en kötü durumda O(n log n).
  • Max-heap: her düğüm çocuklarından büyük ya da eşittir → en büyük öğe köktedir.
  • Ağaç ayrı bir yapı değildir; dizinin kendisidir: dizi[i]'nin çocukları 2i + 1 ve 2i + 2, ebeveyni (i − 1) / 2.
İşleyiş
  1. Dizi max-heap yapısına dönüştürülür.
  2. En büyük öğe (kök) dizinin sonuna yerleştirilir.
  3. Kalan dizi tekrar max-heap yapılır (kök aşağı süzülür).
  4. Tüm öğeler sıralanana kadar tekrarlanır.
1005132431410051324314dizi

Heap Sort

Örnek: [4, 10, 3, 5, 1]

AdımDizi (heap | sıralı)Açıklama
Dizi[4, 10, 3, 5, 1]
Max-heap oluştur[10, 5, 3, 4, 1]kök = en büyük
Kök ↔ dizi[4][1, 5, 3, 4] | [10]10 sıralı bölgeye
Yeniden max-heap yap[5, 4, 3, 1] | [10]kök aşağı süzüldü
Kök ↔ dizi[3][1, 4, 3] | [5, 10]5 sıralı bölgeye
Yeniden max-heap yap[4, 1, 3] | [5, 10]kök aşağı süzüldü
Kök ↔ dizi[2][3, 1] | [4, 5, 10]4 sıralı bölgeye
Yeniden max-heap yap[3, 1] | [4, 5, 10]kök aşağı süzüldü
Kök ↔ dizi[1][1] | [3, 4, 5, 10]3 sıralı bölgeye
Sonuç[1, 3, 4, 5, 10]
410351heap kur105341[4, 10, 3, 5, 1]max-heap

Heap Sort · Adım adım

1. Aşama: Max-Heap Kurma — [6, 5, 3, 1, 8, 7, 2, 4]

60513213847526476051321384752647dizi

Dizi [6, 5, 3, 1, 8, 7, 2, 4] tam ikili ağaç olarak düşünülür: dizi[i]'nin çocukları 2i+1 ve 2i+2. Henüz heap değil.

60513243847526176051324384752617dizi

yiginlastir(i = 3): 1 çocuklarından küçük → yer değiştir (1 ↔ 4). Dizi: [6, 5, 3, 4, 8, 7, 2, 1].

60517243843526176051724384352617dizi

yiginlastir(i = 2): 3 çocuklarından küçük → yer değiştir (3 ↔ 7). Dizi: [6, 5, 7, 4, 8, 3, 2, 1].

60817243543526176081724354352617dizi

yiginlastir(i = 1): 5 çocuklarından küçük → yer değiştir (5 ↔ 8). Dizi: [6, 8, 7, 4, 5, 3, 2, 1].

80617243543526178061724354352617dizi

yiginlastir(i = 0): 6 çocuklarından küçük → yer değiştir (6 ↔ 8). Dizi: [8, 6, 7, 4, 5, 3, 2, 1].

80617243543526178061724354352617dizi

Yaprak olmayan tüm düğümler (i = 3 … 0) işlendi: max-heap [8, 6, 7, 4, 5, 3, 2, 1]. En büyük öğe (8) kökte.

Heap Sort · Adım adım

2. Aşama: Kökü Sona Taşı, Süz

80617243543526178061724354352617dizi

Max-heap: [8, 6, 7, 4, 5, 3, 2, 1]. Her turda kök (en büyük) heap'in son öğesiyle yer değiştirir ve heap bir küçülür.

106172435435261061724354352687dizi

Kök 8 ↔ dizi[7] = 1: 8 sıralı bölgeye (yeşil) geçti. Heap boyutu 7.

706132435415267061324354152687dizi

yiginlastir(0) ile kök aşağı süzülür (1 ↔ 7; 1 ↔ 3) → heap: [7, 6, 3, 4, 5, 1, 2].

2061324354152061324354157687dizi

Kök 7 ↔ dizi[6] = 2: 7 sıralı bölgeye (yeşil) geçti. Heap boyutu 6.

6051324324156051324324157687dizi

yiginlastir(0) ile kök aşağı süzülür (2 ↔ 6; 2 ↔ 5) → heap: [6, 5, 3, 4, 2, 1].

10513243241051324324657687dizi

Kök 6 ↔ dizi[5] = 1: 6 sıralı bölgeye (yeşil) geçti. Heap boyutu 5.

50413213245041321324657687dizi

yiginlastir(0) ile kök aşağı süzülür (1 ↔ 5; 1 ↔ 4) → heap: [5, 4, 3, 1, 2].

204132132041321354657687dizi

Kök 5 ↔ dizi[4] = 2: 5 sıralı bölgeye (yeşil) geçti. Heap boyutu 4.

402132134021321354657687dizi

yiginlastir(0) ile kök aşağı süzülür (2 ↔ 4) → heap: [4, 2, 3, 1].

1021321021324354657687dizi

Kök 4 ↔ dizi[3] = 1: 4 sıralı bölgeye (yeşil) geçti. Heap boyutu 3.

3021123021124354657687dizi

yiginlastir(0) ile kök aşağı süzülür (1 ↔ 3) → heap: [3, 2, 1].

10211021324354657687dizi

Kök 3 ↔ dizi[2] = 1: 3 sıralı bölgeye (yeşil) geçti. Heap boyutu 2.

20112011324354657687dizi

yiginlastir(0) ile kök aşağı süzülür (1 ↔ 2) → heap: [2, 1].

101021324354657687dizi

Kök 2 ↔ dizi[1] = 1: 2 sıralı bölgeye (yeşil) geçti. Heap boyutu 1.

101021324354657687dizi

Heap'te tek öğe kaldı; o da yerinde. Sıralı dizi: [1, 2, 3, 4, 5, 6, 7, 8].

Heap Sort

Heap Sort: Java Kodu ve Analiz

void yiginSirala(int[] dizi) {
  int n = dizi.length;
  for (int i = n / 2 - 1; i >= 0; i--)   // 1) yığın kur
    yiginlastir(dizi, n, i);
  for (int i = n - 1; i > 0; i--) {      // 2) sırala
    takas(dizi, 0, i);                   // en büyüğü sona
    yiginlastir(dizi, i, 0);             // kökü süz
  }
}
void yiginlastir(int[] dizi, int n, int i) {
  int enBuyuk = i, sol = 2 * i + 1, sag = 2 * i + 2;
  if (sol < n && dizi[sol] > dizi[enBuyuk]) enBuyuk = sol;
  if (sag < n && dizi[sag] > dizi[enBuyuk]) enBuyuk = sag;
  if (enBuyuk != i) {
    takas(dizi, i, enBuyuk);
    yiginlastir(dizi, n, enBuyuk);
  }
}
  • Heap kurma: yapraklar (i ≥ n/2) zaten tek öğeli heap'tir; i = n/2 − 1'den köke doğru süzülür. Toplam O(n) (çoğu düğüm alçaktadır).
  • Sıralama: n − 1 kez kök sona alınır ve O(log n)'de süzülür → O(n log n).
  • En kötü durumda bile O(n log n), O(1) ek bellek (yerinde).
  • Kararsız: kök–son takası eşit anahtarların sırasını bozabilir.

Heap, öğeleri tek tek ekleyerek (yukarı süzme) de kurulabilir; bu da geçerli bir max-heap verir ama O(n log n) sürer. Buradaki aşağıdan yukarı kurma (Floyd yöntemi) O(n)'dir.

Heap Sort · Kodu adım adım çalıştır

Max-Heap Kurma: Kodu İzle, dizi = [3, 9, 2, 1, 4, 5]

309122134455392145

dizi = [3, 9, 2, 1, 4, 5]. Yapraklar (indis 3, 4, 5) zaten tek öğeli heap'tir. Kurma i = n / 2 − 1 = 2'den köke doğru ilerler.

309122134455392145

i = 2 (2): sol = 5 (5) > 2 → enBuyuk = sol; sag yok.

309152134425395142

enBuyuk ≠ i: takas(dizi, 2, 5) → 5 yukarı çıkar, 2 aşağı iner; süzme 5 numaralı düğümde sürer (satır 10).

309152134425395142

i = 5 (2): çocuğu yok (sol = 11 ≥ n). enBuyuk = i, süzme biter.

309152134425395142

Döngü i = 1: yiginlastir(dizi, 6, 1).

309152134425395142

i = 1 (9): sol = 3 (1) > 9 değil; sag = 4 (4) > 9 değil. Değişiklik yok: zaten çocuklarından büyük.

309152134425395142

Döngü i = 0: yiginlastir(dizi, 6, 0).

309152134425395142

i = 0 (3): sol = 1 (9) > 3 → enBuyuk = sol; sag = 2 (5) > 9 değil.

903152134425935142

enBuyuk ≠ i: takas(dizi, 0, 1) → 9 yukarı çıkar, 3 aşağı iner; süzme 1 numaralı düğümde sürer (satır 10).

903152134425935142

i = 1 (3): sol = 3 (1) > 3 değil; sag = 4 (4) > 3 → enBuyuk = sag.

904152133425945132

enBuyuk ≠ i: takas(dizi, 1, 4) → 4 yukarı çıkar, 3 aşağı iner; süzme 4 numaralı düğümde sürer (satır 10).

904152133425945132

i = 4 (3): çocuğu yok (sol = 9 ≥ n). enBuyuk = i, süzme biter.

904152133425945132

i = −1: döngü biter. [9, 4, 5, 1, 3, 2] bir max-heap: her ebeveyn çocuklarından büyük, en büyük öğe 9 kökte.

for (int i = n / 2 - 1; i >= 0; i--)
  yiginlastir(dizi, n, i);

void yiginlastir(int[] dizi, int n, int i) {
  int enBuyuk = i, sol = 2 * i + 1, sag = 2 * i + 2;
  if (sol < n && dizi[sol] > dizi[enBuyuk]) enBuyuk = sol;
  if (sag < n && dizi[sag] > dizi[enBuyuk]) enBuyuk = sag;
  if (enBuyuk != i) {
    takas(dizi, i, enBuyuk);
    yiginlastir(dizi, n, enBuyuk);
  }
}

Doğrusal Zamanlı Sıralama

Karşılaştırmalı Sıralamanın Alt Sınırı

  • Yalnızca "ai ≤ aj?" sorusu soran her algoritma bir karar ağacı (decision tree) ile gösterilebilir.
  • Her yaprak bir sıralamadır (permütasyon); doğru çalışmak için n! yaprak gerekir.
  • Yüksekliği h olan ikili ağacın en fazla 2h yaprağı vardır: 2h ≥ n! ⇒ h ≥ log₂(n!) = Ω(n log n).
  • Sonuç: birleştirme sıralaması ve heap sort asimptotik olarak en iyidir.
  • Daha hızlı olmak için karşılaştırma dışında bilgi gerekir: anahtarlar küçük tam sayılar → saymalı, basamak.
≤>≤>≤>≤>≤>1:22:31:3⟨1,2,3⟩1:3⟨2,1,3⟩2:3⟨1,3,2⟩⟨3,1,2⟩⟨2,3,1⟩⟨3,2,1⟩3! = 6 yaprak → yükseklik ≥ ⌈log₂ 6⌉ = 3

Doğrusal Zamanlı Sıralama

Saymalı Sıralama (Counting Sort)

  • Öğeler birbiriyle karşılaştırılmaz.
  • Girdi: A[1 … n], A[j] ∈ {1, 2, …, k}.
  • Çıktı: B[1 … n], sıralı.
  • Geçici: C[1 … k] sayaçları.

Fikir: anahtarı ≤ i olan öğe sayısı biliniyorsa, i anahtarlı son öğe tam o konuma yazılır.

for i = 1 to k
  C[i] = 0
for j = 1 to n
  C[A[j]] = C[A[j]] + 1   // C[i] = |{anahtar = i}|
for i = 2 to k
  C[i] = C[i] + C[i−1]    // C[i] = |{anahtar ≤ i}|
for j = n downto 1
  B[C[A[j]]] = A[j]
  C[A[j]] = C[A[j]] − 1

Doğrusal Zamanlı Sıralama · Adım adım

Saymalı Sıralama Adım Adım: A = [4, 1, 3, 4, 3]

A:4134312345C:1234B:12345

Girdi A = [4, 1, 3, 4, 3], n = 5, anahtarlar {1, …, 4}. C: sayaç dizisi (k = 4), B: çıktı.

A:4134312345C:00001234B:12345

Döngü 1: for i = 1 to k: C[i] = 0 — tüm sayaçlar sıfırlanır. Θ(k).

A:4134312345C:00011234B:12345

Döngü 2, j = 1: A[1] = 4 → C[4]++ = 1. (C[i] = i anahtarının adedi)

A:4134312345C:10011234B:12345

Döngü 2, j = 2: A[2] = 1 → C[1]++ = 1. (C[i] = i anahtarının adedi)

A:4134312345C:10111234B:12345

Döngü 2, j = 3: A[3] = 3 → C[3]++ = 1. (C[i] = i anahtarının adedi)

A:4134312345C:10121234B:12345

Döngü 2, j = 4: A[4] = 4 → C[4]++ = 2. (C[i] = i anahtarının adedi)

A:4134312345C:10221234B:12345

Döngü 2, j = 5: A[5] = 3 → C[3]++ = 2. (C[i] = i anahtarının adedi)

A:4134312345C:11221234B:12345

Döngü 3, i = 2: C[2] = C[2] + C[1] = 1. (C[i] = anahtarı ≤ i olanların adedi)

A:4134312345C:11321234B:12345

Döngü 3, i = 3: C[3] = C[3] + C[2] = 3. (C[i] = anahtarı ≤ i olanların adedi)

A:4134312345C:11351234B:12345

Döngü 3, i = 4: C[4] = C[4] + C[3] = 5. (C[i] = anahtarı ≤ i olanların adedi)

A:4134312345C:11351234B:12345

Önek toplamı hazır: C = [1, 1, 3, 5]. C[i], i anahtarlı son öğenin B'deki konumudur.

A:4134312345C:11251234B:312345

Döngü 4, j = 5: A[5] = 3 → B[C[3] = 3] = 3; C[3]−− = 2.

A:4134312345C:11241234B:3412345

Döngü 4, j = 4: A[4] = 4 → B[C[4] = 5] = 4; C[4]−− = 4.

A:4134312345C:11141234B:33412345

Döngü 4, j = 3: A[3] = 3 → B[C[3] = 2] = 3; C[3]−− = 1.

A:4134312345C:01141234B:133412345

Döngü 4, j = 2: A[2] = 1 → B[C[1] = 1] = 1; C[1]−− = 0.

A:4134312345C:01131234B:1334412345

Döngü 4, j = 1: A[1] = 4 → B[C[4] = 4] = 4; C[4]−− = 3.

A:4134312345C:01131234B:1334412345

Sonuç B = [1, 3, 3, 4, 4]. Hiç karşılaştırma yapılmadı; sondan başa gezildiği için eşit anahtarların sırası korunur (kararlı).

Doğrusal Zamanlı Sıralama

Saymalı Sıralama: Karmaşıklık ve Java

DöngüİşSüre
1C[1..k] = 0Θ(k)
2saymaΘ(n)
3önek toplamıΘ(k)
4B'ye yerleştirΘ(n)
ToplamΘ(n + k)
int[] saymaliSirala(int[] dizi) {
  int maks = enBuyuk(dizi);
  int[] sayac = new int[maks + 1];
  for (int x : dizi) sayac[x]++;
  for (int i = 1; i <= maks; i++) sayac[i] += sayac[i - 1];
  int[] cikti = new int[dizi.length];
  for (int i = dizi.length - 1; i >= 0; i--) {
    cikti[sayac[dizi[i]] - 1] = dizi[i];
    sayac[dizi[i]]--;
  }
  return cikti;
}
  • k = O(n) ise Θ(n): Ω(n log n) sınırını aşar, çünkü karşılaştırma yapmaz.
  • Ek bellek Θ(n + k); k çok büyükse (ör. 32 bitlik tam sayılar) pratik değildir. Java sürümü 0-tabanlıdır ve 0 … maks aralığını kullanır.
  • Son döngünün sondan başa gezmesi kararlılığı sağlar → basamak sıralamasının temeli.

Doğrusal Zamanlı Sıralama

Basamak Sıralaması (Radix Sort)

  • Tam sayıları basamak basamak sıralar; en anlamsız basamaktan (birler) başlar: LSD.
  • Her geçişte o basamağa göre kararlı bir sıralama (saymalı, k = 10) yapılır.
  • Kararlılık şarttır: onlar basamağına göre sıralarken birler sırası korunmalıdır.
  • d basamak, taban b: Θ(d · (n + b)). d sabitse Θ(n).
  • Ek bellek Θ(n + b); yerinde değildir.
int[] basamakSirala(int[] dizi) {
  int maks = enBuyuk(dizi);
  for (int us = 1; maks / us > 0; us *= 10)
    dizi = basamagaGoreSay(dizi, us);
  return dizi;
}
int[] basamagaGoreSay(int[] dizi, int us) {
  int n = dizi.length;
  int[] cikti = new int[n], sayac = new int[10];
  for (int x : dizi) sayac[(x / us) % 10]++;
  for (int i = 1; i < 10; i++) sayac[i] += sayac[i - 1];
  for (int i = n - 1; i >= 0; i--) {
    int b = (dizi[i] / us) % 10;
    cikti[--sayac[b]] = dizi[i];
  }
  return cikti;
}

Doğrusal Zamanlı Sıralama · Adım adım

Basamak Sıralaması Adım Adım

Girdi17045759080224266

Girdi [170, 45, 75, 90, 802, 24, 2, 66]. En büyük sayı 802: 3 basamak → 3 geçiş (en anlamsız basamaktan başlayarak, LSD).

us = 1: birler basamağı1700455755900802224422666

Geçiş 1: her sayının birler basamağı (altta) anahtar olarak kullanılır; eksik basamak 0 sayılır.

birler basamağına göre sıralı1700900802222244455755666

Kararlı saymalı sıralama sonrası: [170, 90, 802, 2, 24, 45, 75, 66]. Eşit basamaklılar önceki sıralarını korudu.

us = 10: onlar basamağı1707909802020242454757666

Geçiş 2: her sayının onlar basamağı (altta) anahtar olarak kullanılır; eksik basamak 0 sayılır.

onlar basamağına göre sıralı8020202424546661707757909

Kararlı saymalı sıralama sonrası: [802, 2, 24, 45, 66, 170, 75, 90]. Eşit basamaklılar önceki sıralarını korudu.

us = 100: yüzler basamağı8028202404506601701750900

Geçiş 3: her sayının yüzler basamağı (altta) anahtar olarak kullanılır; eksik basamak 0 sayılır.

yüzler basamağına göre sıralı2024045066075090017018028

Kararlı saymalı sıralama sonrası: [2, 24, 45, 66, 75, 90, 170, 802]. Tüm basamaklar işlendi → sıralı.

Doğrusal Zamanlı Sıralama

Basamak Sıralaması: Kararlılık Neden Gerekli?

girdi456167276467273123birler273123456276167467onlar123456167467273276yüzler123167273276456467
  • Yeşil sütunlar, o ana kadar sıralı hâle gelen son eklerdir: k geçişten sonra dizi, son k basamağa göre sıralıdır.
  • 2. geçişte 167 ile 467'nin onlar basamağı eşittir (6); 1. geçişten gelen sıra (7 = 7, giriş sırası) korunur.
  • Alt sıralama kararsız olsaydı, örneğin 273 ile 276 son geçişte yer değiştirebilir ve sonuç bozulurdu.

Doğrusal Zamanlı Sıralama · Kodu adım adım çalıştır

basamagaGoreSay(dizi, 1): dizi = [32, 15, 41, 23, 11]

dizi3215412311sayac00010203040506070809cikti01234

us = 1: birler basamağına göre sıralanacak. sayac[0..9] sıfır, cikti boş.

dizi3215412311sayac00011203040506070809cikti01234

x = 32: basamak (32 / 1) % 10 = 2 → sayac[2]++ = 1.

dizi3215412311sayac00011203041506070809cikti01234

x = 15: basamak (15 / 1) % 10 = 5 → sayac[5]++ = 1.

dizi3215412311sayac00111203041506070809cikti01234

x = 41: basamak (41 / 1) % 10 = 1 → sayac[1]++ = 1.

dizi3215412311sayac00111213041506070809cikti01234

x = 23: basamak (23 / 1) % 10 = 3 → sayac[3]++ = 1.

dizi3215412311sayac00211213041506070809cikti01234

x = 11: basamak (11 / 1) % 10 = 1 → sayac[1]++ = 2.

dizi3215412311sayac00213243445556575859cikti01234

Önek toplamı: sayac[b] artık basamağı ≤ b olan öğe sayısıdır; ör. sayac[3] = 4. Bu sayı, o basamaklı son öğenin cikti'daki konumunun bir fazlasıdır.

dizi3215412311sayac00113243445556575859cikti0111234

i = 4: x = 11, b = 1. --sayac[1] = 1 → cikti[1] = 11.

dizi3215412311sayac00113233445556575859cikti011122334

i = 3: x = 23, b = 3. --sayac[3] = 3 → cikti[3] = 23.

dizi3215412311sayac00013233445556575859cikti41011122334

i = 2: x = 41, b = 1. --sayac[1] = 0 → cikti[0] = 41. 41 ile 11'in basamağı aynı; sağdan sola gezildiği için 41 (girdide önce) 11'in soluna düştü: kararlı.

dizi3215412311sayac00013233444556575859cikti4101112233154

i = 1: x = 15, b = 5. --sayac[5] = 4 → cikti[4] = 15.

dizi3215412311sayac00012233444556575859cikti410111322233154

i = 0: x = 32, b = 2. --sayac[2] = 2 → cikti[2] = 32.

dizi3215412311sayac00012233444556575859cikti410111322233154

cikti = [41, 11, 32, 23, 15]: birler basamağına göre sıralı. Sonraki geçiş us = 10 ile onlar basamağına bakar; kararlılık sayesinde birler sırası korunur.

int[] basamagaGoreSay(int[] dizi, int us) {
  int n = dizi.length;
  int[] cikti = new int[n], sayac = new int[10];
  for (int x : dizi) sayac[(x / us) % 10]++;
  for (int i = 1; i < 10; i++) sayac[i] += sayac[i - 1];
  for (int i = n - 1; i >= 0; i--) {
    int b = (dizi[i] / us) % 10;
    cikti[--sayac[b]] = dizi[i];
  }
  return cikti;
}

Doğrusal Zamanlı Sıralama

Kova Sıralaması (Bucket Sort)

  • Girdi [0, 1) aralığına düzgün dağılmış sayılar olsun.
  • n kova açılır; x değeri ⌊n · x⌋ numaralı kovaya atılır.
  • Her kova (eklemeli sıralamayla) sıralanır, kovalar sırayla birleştirilir.
  • Beklenen süre Θ(n); tüm öğeler tek kovaya düşerse en kötü Θ(n²).
  • Simülatördeki onuncu algoritmadır; dağılım hakkında varsayım yapar.
A = .78, .17, .39, .26, .72, .94, .21, .12, .23, .680∅1.12.172.21.23.263.394∅5∅6.687.72.788∅9.94Birleştir: .12, .17, .21, .23, .26, .39, .68, .72, .78, .94

Timsort

Timsort: Hibrit Sıralama

  • Tim Peters (2002, Python). Java'da nesne dizileri (Arrays.sort(Object[]), List.sort) ve Python'da sorted Timsort kullanır.
  • Gerçek veride sık görülen sıralı parçaları (run) kullanır: kısa run'lar eklemeli sıralamayla uzatılır, run'lar birleştirme sıralamayla birleştirilir.
  • Kararlı; en kötü O(n log n), sıralı girdide Θ(n); O(n) ek bellek.
static final int MIN_PARCA = 4;
void timSirala(int[] dizi) {
  int n = dizi.length;
  for (int i = 0; i < n; i += MIN_PARCA)            // 1) run'lar
    eklemeliSirala(dizi, i, Math.min(i + MIN_PARCA - 1, n - 1));
  for (int boyut = MIN_PARCA; boyut < n; boyut *= 2)  // 2) birleştir
    for (int sol = 0; sol < n; sol += 2 * boyut) {
      int orta = sol + boyut - 1;
      int sag = Math.min(sol + 2 * boyut - 1, n - 1);
      if (orta < sag) birlestir(dizi, sol, orta, sag);
    }
}

Buradaki sürüm sabit uzunluklu run'larla basitleştirilmiştir (gerçek Timsort'ta minrun 32–64, doğal run tespiti ve "galloping" vardır).

Timsort · Adım adım

Timsort Adım Adım (MIN_PARCA = 4)

Girdi, MIN_PARCA = 45021172233194105361278819

Dizi [5, 21, 7, 23, 19, 10, 3, 12, 8, 1], n = 10. Dizi 4'erli parçalara (run) ayrılır (renkler).

eklemeliSirala(0, 3)5071212233194105361278819

Run [0..3] eklemeli sıralama ile sıralandı: [5, 7, 21, 23].

eklemeliSirala(4, 7)5071212233341051261978819

Run [4..7] eklemeli sıralama ile sıralandı: [3, 10, 12, 19].

eklemeliSirala(8, 9)5071212233341051261971889

Run [8..9] eklemeli sıralama ile sıralandı: [1, 8].

boyut = 4: birlestir(0, 3, 7)3051721031241952162371889

boyut = 4: [5, 7, 21, 23] + [3, 10, 12, 19] birleştirildi → [3, 5, 7, 10, 12, 19, 21, 23].

boyut = 4: [8..9] tek başına3051721031241952162371889

boyut = 4: [8..9] parçasının birleşeceği eşi yok (orta = 11 ≥ sag = 9) → aynen kalır.

boyut = 8: birlestir(0, 7, 9)1031527384105126197218239

boyut = 8: [3, 5, 7, 10, 12, 19, 21, 23] + [1, 8] birleştirildi → [1, 3, 5, 7, 8, 10, 12, 19, 21, 23]. Dizi sıralandı.

Karşılaştırma

Sıralama Algoritmalarının Karşılaştırılması

AlgoritmaEn iyiOrtalamaEn kötüEk bellekKararlıYerinde
Kabarcık (bayraklı)Θ(n)Θ(n²)Θ(n²)O(1)EvetEvet
EklemeliΘ(n)Θ(n²)Θ(n²)O(1)EvetEvet
SeçimliΘ(n²)Θ(n²)Θ(n²)O(1)HayırEvet
Shell (n/2 aralık)Θ(n log n)aralığa bağlıΘ(n²)O(1)HayırEvet
BirleştirmeΘ(n log n)Θ(n log n)Θ(n log n)Θ(n)EvetHayır
HızlıΘ(n log n)Θ(n log n)Θ(n²)O(log n)*HayırEvet
Heap sortO(n log n)Θ(n log n)Θ(n log n)O(1)HayırEvet
SaymalıΘ(n + k)Θ(n + k)Θ(n + k)Θ(n + k)EvetHayır
Basamak (LSD)Θ(d(n + b))Θ(d(n + b))Θ(d(n + b))Θ(n + b)EvetHayır
KovaΘ(n)Θ(n)†Θ(n²)Θ(n)EvetHayır
TimsortΘ(n)Θ(n log n)Θ(n log n)O(n)EvetHayır

* özyineleme yığını (küçük parçaya önce inilirse). † düzgün dağılımda beklenen. k: anahtar aralığı, d: basamak sayısı, b: taban. Timsort'un Θ(n) en iyi durumu doğal run tespitiyle gerçek sürüm içindir.

Karşılaştırma

Kaç Karşılaştırma? n = 1000

AlgoritmaRastgeleSıralıTers sıralı
Kabarcık (bayraklı)497.960999499.500
Eklemeli252.205999499.500
Seçimli499.500499.500499.500
Shell (n/2)14.7238.00611.716
Birleştirme8.6935.0444.932
Hızlı (son öğe pivot)11.384499.500499.500
Heap sort16.79117.58315.965
  • Öğe karşılaştırma sayıları; bu bölümdeki kodlar n = 1000 için çalıştırılarak sayıldı (rastgele dizi sabit tohumla üretildi).
  • Karşılaştırma için: n² / 2 ≈ 500.000, n log₂ n ≈ 9.966. Sıralı girdide son öğe pivotlu hızlı sıralama en kötü durumuna düşer.

Karşılaştırma

Hangi Durumda Hangi Algoritma?

Küçük ya da neredeyse sıralıEklemeli sıralama: az ek yük, uyarlanabilir, kararlı.
Genel amaçlı, hızHızlı sıralama (rastgele / üçün ortancası pivot); önbellek dostu, yerinde.
Kararlılık gerekliBirleştirme sıralaması ya da Timsort (kütüphanelerin nesne sıralaması).
En kötü durum garantisi, az bellekHeap sort: O(n log n) ve O(1) ek bellek (introsort'un yedeği).
Küçük tam sayı anahtarlarSaymalı ya da basamak sıralaması: Θ(n + k), Θ(d(n + b)).
Bağlı liste, dış bellekBirleştirme sıralaması: rastgele erişim gerektirmez; disk üzerindeki büyük dosyalar parça parça birleştirilir.

Kabarcık ve seçimli sıralama öğretim amaçlıdır; seçimli yalnızca yazmanın çok pahalı olduğu durumlarda anlamlıdır.

Özet

Özet

KonuHatırlanacaklar
Ölçütlerzaman (en iyi/ortalama/en kötü), ek bellek, kararlılık, yerinde, uyarlanabilirlik
Kabarcıkkomşu takas; tur sonunda en büyük sonda; bayrakla en iyi Θ(n), aksi Θ(n²); kararlı
Eklemelianahtarı sakla, büyükleri kaydır, yerleştir; Θ(n + ters çift); küçük/neredeyse sıralı veride en iyi
Seçimlien küçüğü bul, başa al; her zaman n(n − 1)/2 karşılaştırma, ≤ n − 1 takas; kararsız
Shellazalan aralıklarla eklemeli sıralama; yerinde, kararsız
Birleştirmeböl–sırala–birleştir; T(n) = 2T(n/2) + Θ(n) = Θ(n log n); Θ(n) ek bellek; kararlı
Hızlıpivot etrafında bölümle; ortalama Θ(n log n), en kötü Θ(n²); yerinde, kararsız
Heap sortO(n) max-heap kur, n − 1 kez kökü sona al ve süz; O(n log n), O(1) ek bellek
Doğrusalkarşılaştırmalı alt sınır Ω(n log n); saymalı Θ(n + k), basamak Θ(d(n + b)), kova beklenen Θ(n)

Özet

Etkileşimli Simülatörler

Sıralama AlgoritmalarıOn algoritma (kabarcık, eklemeli, seçimli, birleştirme, hızlı, saymalı, basamak, kova, heap, Shell) çubuk grafik üzerinde adım adım; karşılaştırılan ve sıralanan öğeler, işlem günlüğü ve karmaşıklık tablosu.
Sıralama YarışıKabarcık, eklemeli, seçimli ve hızlı sıralama aynı rastgele dizi (8–40 öğe) üzerinde yan yana yarışır; karşılaştırma ve takas sayıları karşılaştırılır.
Sıralama Özellikleri LaboratuvarıEşit anahtarlı kayıtlar (3, A), (1, B), (3, C) … eklemeli ya da seçimli sıralamayla sıralanır; göreli sıranın korunup korunmadığı (kararlılık) görülür.

Özet

Sık Yapılan Hatalar

Dizi sınırını aşmakKabarcıkta iç döngü j < n − 1 − i olmalı; j < n yazmak dizi[j+1] ile taşar.
Anahtarı saklamamakEklemeli sıralamada gecici önceden alınmazsa ilk kaydırma onu ezer.
En küçüğü değer olarak tutmakSeçimli sıralamada indis tutulmazsa takas yapılamaz.
Kararlılığı bozmakBirleştirmede <= yerine <, saymalıda baştan sona gezmek eşit anahtarların sırasını bozar.
Pivotu özyinelemeye katmakhizliSirala(dizi, alt, p) yazmak pivotu tekrar işler; iki öğe kalınca sonsuz özyineleme olabilir.
"Quicksort her zaman n log n"Sıralı girdide sabit pivot Θ(n²) ve n derinlikli özyineleme (StackOverflowError) verir.

Özet

Örnek Problemler

  1. [5, 2, 4, 6, 1, 3] dizisine bayraklı kabarcık sıralaması uygulanıyor. Her tur sonundaki diziyi yazın.
  2. Aynı diziyi eklemeli sıralama kaç karşılaştırma ve kaç kaydırma ile sıralar? Seçimli sıralama kaç takas yapar?
  3. parcala (Lomuto, pivot = son öğe) [2, 8, 7, 1, 3, 5, 6, 4] üzerinde çalışınca dizi ve dönüş değeri ne olur?
  4. [4, 10, 3, 5, 1] dizisinden aşağıdan yukarı kurulan max-heap nedir?
  5. A = [2, 5, 3, 0, 2, 3, 0, 3] (anahtarlar 0 … 5) için saymalı sıralamanın 3. döngüden sonraki C dizisi nedir?
  6. Birleştirme sıralaması 8 öğeyi en fazla kaç karşılaştırmayla sıralar?
Cevapları göster
  1. [2, 4, 5, 1, 3, 6] → [2, 4, 1, 3, 5, 6] → [2, 1, 3, 4, 5, 6] → [1, 2, 3, 4, 5, 6] → [1, 2, 3, 4, 5, 6] (son turda takas yok → durur).
  2. Eklemeli: 12 karşılaştırma, 9 kaydırma (= ters çift sayısı). Seçimli: 15 karşılaştırma, 3 takas.
  3. [2, 1, 3, 4, 7, 5, 6, 8], dönüş 3 (pivot 4 indis 3'te).
  4. [10, 5, 3, 4, 1]: önce i = 1 (10 zaten büyük), sonra i = 0: 4 ↔ 10, 4 ↔ 5.
  5. C = [2, 2, 4, 7, 7, 8] (adetler [2, 0, 2, 3, 0, 1] ve önek toplamları).
  6. Her düzeyde birleştirilen m öğe en fazla m − 1 karşılaştırma ister: 4·1 + 2·3 + 1·7 = 17.

Özet

Alıştırmalar

  1. n = 6 öğeli ters sıralı dizide kabarcık sıralaması kaç karşılaştırma ve kaç takas yapar?
  2. Seçimli sıralamanın kararsız olduğunu gösteren üç öğeli bir örnek verin.
  3. Eklemeli sıralamada doğru konumu ikili arama ile bulursak zaman karmaşıklığı ne olur?
  4. Hızlı sıralamayı (son öğe pivot) zaten sıralı 1000 öğeli diziyle çağırınca ne olur? Nasıl düzeltilir?
  5. [329, 457, 657, 839, 436, 720, 355] dizisini LSD basamak sıralaması ile sıralayın; her geçişten sonraki diziyi yazın.
  6. Bir dizideki ters çift sayısını O(n log n)'de bulan bir yöntem önerin.
Cevaplar / ipuçları
  1. Her tur tüm çiftler ters: 5 + 4 + 3 + 2 + 1 = 15 karşılaştırma ve 15 takas.
  2. [2ₐ, 2ᵦ, 1] → ilk turda 1 ile 2ₐ yer değiştirir → [1, 2ᵦ, 2ₐ].
  3. Karşılaştırmalar O(n log n)'e iner ama kaydırmalar hâlâ Θ(n²) → toplam yine Θ(n²).
  4. Her bölümleme yalnızca pivotu ayırır: 999 + 998 + … + 1 = 499.500 karşılaştırma, 1000 derinlikli özyineleme. Rastgele pivot ya da üçün ortancası.
  5. Birler: [720, 355, 436, 457, 657, 329, 839]; onlar: [720, 329, 436, 839, 355, 457, 657]; yüzler: [329, 355, 436, 457, 657, 720, 839].
  6. Birleştirme sıralaması şöyle değiştirilir: sağdan bir öğe alındığında sol yarıda kalan öğe sayısı (L.length − i) kadar ters çift eklenir; toplam O(n log n).

Özet

Kaynaklar

  • Cormen, Leiserson, Rivest ve Stein, Introduction to Algorithms, 4. baskı, MIT Press, 2022 (Bölüm 2, 6, 7, 8).
  • Sedgewick ve Wayne, Algorithms, 4. baskı, Addison-Wesley, 2011 (Bölüm 2: Sorting).
  • D. E. Knuth, The Art of Computer Programming, Vol. 3: Sorting and Searching, 2. baskı, 1998.
  • E. D. Demaine ve C. E. Leiserson, MIT 6.046J Introduction to Algorithms ders notları, 2005 (bölümleme ve saymalı sıralama örnekleri).
  • C. A. R. Hoare, "Quicksort", The Computer Journal 5(1), 1962; D. L. Shell, "A High-Speed Sorting Procedure", CACM 2(7), 1959.
  • T. Peters, "listsort.txt" (Timsort tasarım notu), CPython, 2002.

Son

Bölüm 2: Sıralama Algoritmaları
Sonraki bölüm: Bölüm 3: Arama Algoritmaları · Terim sözlüğü
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.