SEN2211 · 13. hafta · Sorting Algorithms I

Sıralama I: bubble, selection, insertion

Üç temel O(n²) sıralama algoritması, her geçişten sonra dizinin hali, karşılaştırma ve takas sayıları ve kararlılık (stability). Sınavda “show the array after each pass” sorusu neredeyse garanti.

sortingbubble sortselection sortinsertion sortpasscomparisonswapshiftearly terminationin-placestable sortinversionadaptive

Sıralama (sorting), bilgisayar bilimlerinin en çok çalışılan problemidir: veriyi sıralarsan arama O(log n)‘e düşer, tekrarlar yan yana gelir, en küçük/en büyük hemen bulunur. Bu hafta üç basit algoritma var. Üçü de O(n²) ve büyük veride yavaş, ama mantıkları sezgisel ve sınavda geçiş geçiş iz istenir. Bir sonraki hafta O(n log n) algoritmalara geçeceğiz.

Altın kurallar:

  1. Bubble: her geçişte en büyük eleman sona “kabarcıklanır”.
  2. Selection: her geçişte kalan kısmın en küçüğü başa seçilir.
  3. Insertion: her geçişte bir sonraki eleman, soldaki sıralı kısımda doğru yerine sokulur.
  4. “Pass” tanımına dikkat. Bu sayfada geçiş = dış döngünün bir turu.

Bubble sort

Komşu iki elemanı karşılaştır; soldaki büyükse takas et. Bir geçiş boyunca en büyük eleman, köpük gibi en sona çıkar. Sonraki geçişin son elemana bakmasına gerek yoktur.

static void bubbleSort(int[] a) {
    int n = a.length;
    for (int pass = 1; pass < n; pass++) {
        boolean swapped = false;
        for (int j = 0; j < n - pass; j++) {
            if (a[j] > a[j + 1]) {
                int t = a[j]; a[j] = a[j + 1]; a[j + 1] = t;
                swapped = true;
            }
        }
        if (!swapped) break;   // takas yoksa dizi sıralı
    }
}

{7, 3, 9, 1, 5} üzerinde her geçişten sonra:

pass 1: [3, 7, 1, 5, 9]
pass 2: [3, 1, 5, 7, 9]
pass 3: [1, 3, 5, 7, 9]
pass 4: [1, 3, 5, 7, 9]
comps=10 swaps=6 inversions(orig)=6

Geçiş 1’in içi, karşılaştırma karşılaştırma:

[7, 3, 9, 1, 5]   7 > 3 takas  → [3, 7, 9, 1, 5]
                  7 < 9        → değişiklik yok
                  9 > 1 takas  → [3, 7, 1, 9, 5]
                  9 > 5 takas  → [3, 7, 1, 5, 9]   9 yerine oturdu

Geçiş 3’te dizi sıralı hale geldi, ama o geçişte bir takas yapıldığı için algoritma bunu bilemez; geçiş 4 takassız biter ve durur.

Ters çevrim (inversion): i < j iken a[i] > a[j] olan çift. Her komşu takas tam olarak bir ters çevrimi düzeltir; bu yüzden bubble sort’un takas sayısı = ters çevrim sayısı.

Selection sort

Kalan kısmı tara, en küçüğün indeksini bul, onu kalan kısmın başıyla takas et. Baştaki kısım her geçişte bir büyür ve nihai haldedir.

static void selectionSort(int[] a) {
    for (int i = 0; i < a.length - 1; i++) {
        int min = i;
        for (int j = i + 1; j < a.length; j++)
            if (a[j] < a[min]) min = j;
        int t = a[i]; a[i] = a[min]; a[min] = t;
    }
}

{38, 12, 45, 7, 29, 16}:

pass 1: [7, 12, 45, 38, 29, 16]
pass 2: [7, 12, 45, 38, 29, 16]
pass 3: [7, 12, 16, 38, 29, 45]
pass 4: [7, 12, 16, 29, 38, 45]
pass 5: [7, 12, 16, 29, 38, 45]
comps=15 swaps=3

Geçiş 2 ve 5’te en küçük zaten yerindeydi, gerçek takas olmadı (sayaçta sadece min != i olan takaslar sayıldı). Karşılaştırma sayısı girdiden bağımsız: her zaman n(n−1)2\frac{n(n-1)}{2}. Sıralı bir dizi verdiğinde de 15 karşılaştırma yapar.

TUZAK · Selection sort erken duramaz. Bubble’daki bayrak fikri burada işe yaramaz; minimumu bulmak için kalan kısmın hepsini taramak zorundasın. En iyi durum da O(n²).

Insertion sort

Kart oyununda elindeki kartları dizer gibi: her yeni kartı alır, soldaki sıralı kartların arasında doğru yere sokarsın. Büyük kartlar bir sağa kayar.

static void insertionSort(int[] a) {
    for (int i = 1; i < a.length; i++) {
        int key = a[i];
        int j = i - 1;
        while (j >= 0 && a[j] > key) {
            a[j + 1] = a[j];   // kaydır
            j--;
        }
        a[j + 1] = key;
    }
}

{38, 12, 45, 7, 29, 16}:

pass 1: [12, 38, 45, 7, 29, 16]
pass 2: [12, 38, 45, 7, 29, 16]
pass 3: [7, 12, 38, 45, 29, 16]
pass 4: [7, 12, 29, 38, 45, 16]
pass 5: [7, 12, 16, 29, 38, 45]
comps=12 shifts=9 inversions=9

Geçiş 3’ün içi (key = 7):

[12, 38, 45, 7, 29, 16]   key = 7
45 > 7 → kaydır    [12, 38, 45, 45, 29, 16]
38 > 7 → kaydır    [12, 38, 38, 45, 29, 16]
12 > 7 → kaydır    [12, 12, 38, 45, 29, 16]
j = -1, dur        [7, 12, 38, 45, 29, 16]

Insertion sort uyarlanabilir (adaptive): dizi ne kadar sıralıysa o kadar hızlı. Sıralı dizide n − 1 karşılaştırma, ters sıralıda n(n−1)2\frac{n(n-1)}{2}:

insertion sorted: comps=5 shifts=0
insertion reverse: comps=15 shifts=15

Geçişten algoritmayı tanımak

Sınavda bazen ara durum verilip “hangi algoritma?” diye sorulur. Aynı girdi {4, 2, 6, 1, 3}, ilk geçişten sonra:

AlgoritmaGeçiş 1 sonrasıİz
Bubble[2, 4, 1, 3, 6]en büyük (6) sonda, diğerleri bir kaydı
Selection[1, 2, 6, 4, 3]en küçük (1) başta, eski baştaki (4) 1’in yerinde
Insertion[2, 4, 6, 1, 3]ilk iki eleman sıralandı, gerisi dokunulmamış

Kararlılık (stability)

Eşit anahtarlı elemanların sıralamadan sonra orijinal sıralarını koruması. Önce isme göre sıralı bir öğrenci listesini nota göre sıraladığında, aynı notu alanlar isme göre sıralı kalsın istersin; bu ancak kararlı bir algoritmayla olur.

Anahtarları 3, 3, 1 olan kayıtlar (harfler orijinal sırayı gösteriyor):

selection [1, 3b, 3a] insertion [1, 3a, 3b] bubble [1, 3a, 3b]

Selection sort uzak takas yapar: 1’i başa getirirken 3a’yı en sona fırlatır ve 3b’nin önünden atlatır. Bubble ve insertion sadece komşuları ve sadece kesin büyükse (>) yer değiştirir, eşitler birbirini geçmez.

Karşılaştırma tablosu

Bubble (bayraklı)SelectionInsertion
En iyiO(n)O(n²)O(n)
OrtalamaO(n²)O(n²)O(n²)
En kötüO(n²)O(n²)O(n²)
Takas / yazmaçok (= ters çevrim)en fazla n − 1çok (kaydırma)
Ek bellekO(1)O(1)O(1)
Kararlıevethayırevet
Uyarlanabilirevethayırevet

Rastgele dizilerde karşılaştırma sayısı (n her seferinde iki kat):

n=1000 bubble comps=498275 selection comps=499500 insertion comps=245712
n=2000 bubble comps=1996855 selection comps=1999000 insertion comps=985303
n=4000 bubble comps=7996674 selection comps=7998000 insertion comps=3980580

Hepsi x4 büyüyor: karesel. Insertion sort ortalamada diğerlerinin yarısı kadar karşılaştırma yapıyor, çünkü her eleman sıralı kısmın ortalama yarısında durur.

Sık yapılan hatalar

YanlışDoğrusu
Bubble iç döngüsü j < nj < n - pass (yoksa a[j + 1] dışarı taşar ve gereksiz karşılaştırma)
Selection’da her küçük bulunduğunda takasÖnce minimumun indeksini bul, geçiş sonunda tek takas
Insertion’da key’i saklamamakKaydırma a[i]‘nin üstüne yazar; int key = a[i];
Insertion’da a[j] >= keyKararlılığı bozar; >
Selection sıralı dizide hızlıdırHer zaman n(n−1)/2 karşılaştırma
Selection kararlıdırUzak takas eşitlerin sırasını bozabilir
Insertion’ın baştaki kısmı nihaiSadece kendi içinde sıralı; sonradan araya eleman girer
Bubble her durumda n − 1 geçişBayrakla takassız geçişte durur

Kendini test et

Sınavdaki gibi İngilizce sorular. Önce kâğıt kalemle çöz, sonra cevabı aç.

Soru 1kolay

Bubble sort (adjacent swaps, largest element bubbles to the end) is applied to {7, 3, 9, 1, 5}. Show the array after pass 1 and after pass 2.

Cevabı göster
pass 1: [3, 7, 1, 5, 9]; pass 2: [3, 1, 5, 7, 9]

Geçiş 1: (7,3) takas → 3 7; (7,9) tamam; (9,1) takas; (9,5) takas → [3, 7, 1, 5, 9]. En büyük 9 sona yerleşti. Geçiş 2 (son eleman hariç): (3,7) tamam; (7,1) takas; (7,5) takas → [3, 1, 5, 7, 9].

Soru 2orta

For the same input {7, 3, 9, 1, 5}, how many comparisons and how many swaps does bubble sort (with the early-exit flag) make in total?

Cevabı göster
10 comparisons, 6 swaps

Geçiş 3 sonunda dizi sıralı ama o geçişte takas olduğu için geçiş 4 de çalışır ve takassız biter. Karşılaştırma 4 + 3 + 2 + 1 = 10. Takas sayısı dizideki ters çevrim (inversion, i < j ve a[i] > a[j] çifti) sayısına eşittir: (7,3), (7,1), (7,5), (3,1), (9,1), (9,5) = 6.

Soru 3kolay

Selection sort (find the minimum of the unsorted part, swap it to the front) is applied to {38, 12, 45, 7, 29, 16}. Show the array after passes 1, 2 and 3.

Cevabı göster
[7, 12, 45, 38, 29, 16], [7, 12, 45, 38, 29, 16], [7, 12, 16, 38, 29, 45]

Geçiş 1: en küçük 7, 38 ile takas. Geçiş 2: kalan kısmın en küçüğü 12 zaten yerinde, değişiklik yok. Geçiş 3: kalanların en küçüğü 16, 45 ile takas. Geçişte değişiklik olmaması selection sort'u durdurmaz.

Soru 4orta

Insertion sort is applied to {38, 12, 45, 7, 29, 16}. Show the array after passes 1 to 3 (pass i inserts a[i] into the sorted prefix).

Cevabı göster
[12, 38, 45, 7, 29, 16], [12, 38, 45, 7, 29, 16], [7, 12, 38, 45, 29, 16]

Geçiş 1: 12, 38'in önüne girer. Geçiş 2: 45 zaten büyük, yerinde kalır (1 karşılaştırma). Geçiş 3: 7, üç elemanı sağa kaydırıp başa girer. Selection sort'tan farkı: baştaki sıralı kısım nihai değil; sonradan gelen küçük elemanlar araya girebilir.

Soru 5orta

How many comparisons does selection sort make on an array of 6 elements? Does it depend on the input order?

Cevabı göster
15, no

Geçiş i'de kalan n − i eleman taranır: 5 + 4 + 3 + 2 + 1 = 15 = n(n−1)2\frac{n(n-1)}{2}. Dizi zaten sıralı olsa da aynı: program sıralı dizide de 15 karşılaştırma, 0 takas saydı. Selection sort girdiye duyarsızdır (non-adaptive).

Soru 6orta

Bubble sort with the early-exit flag is run on an already sorted array of 6 elements. How many comparisons are made? What is its best-case Big-O?

Cevabı göster
5, O(n)

İlk geçişte n − 1 = 5 karşılaştırma yapılır, hiç takas olmaz, bayrak false kalır ve algoritma durur. En iyi durum O(n). Bayrak olmasaydı her durumda n(n−1)/2 = 15 karşılaştırma yapardı.

Soru 7orta

Insertion sort on 6 elements: how many comparisons for an already sorted array, and how many for a reverse-sorted array {6, 5, 4, 3, 2, 1}?

Cevabı göster
5 and 15

Sıralıda her yeni eleman solundakiyle bir kez karşılaştırılır ve yerinde kalır: n − 1 = 5 (en iyi O(n)). Ters sıralıda i. eleman i kez karşılaştırılıp başa kaydırılır: 1 + 2 + 3 + 4 + 5 = 15, kaydırma da 15 (en kötü O(n²)). Kaydırma sayısı her zaman ters çevrim sayısına eşittir.

Soru 8zor

Records with keys 3a, 3b, 1 (the letters only mark the original order) are sorted by key. What does each algorithm produce, and which ones are stable?

Cevabı göster
selection: 1 3b 3a (not stable); insertion and bubble: 1 3a 3b (stable)

Selection sort geçiş 1'de en küçük 1'i bulup ilk eleman 3a ile takas eder: 1, 3b, 3a. Uzak takas 3a'yı 3b'nin arkasına atladı, eşitlerin sırası bozuldu. Insertion ve bubble sadece komşuları ve sadece > ise yer değiştirdiği için eşitler sıralarını korur. Kararlılık, örneğin önce isme sonra nota göre sıralarken önemlidir.

Soru 9orta

Write static void insertionSort(int[] a).

Cevabı göster
For i = 1..n-1: key = a[i]; shift larger elements of a[0..i-1] right; place key.

static void insertionSort(int[] a) {
    for (int i = 1; i < a.length; i++) {
        int key = a[i];
        int j = i - 1;
        while (j >= 0 && a[j] > key) {
            a[j + 1] = a[j];   // büyükleri sağa kaydır
            j--;
        }
        a[j + 1] = key;        // boşluğa yerleştir
    }
}
key'i önceden saklamak şart; kaydırma a[i]'nin üstüne yazar. a[j] > key yerine >= yazarsan algoritma kararsız olur.

Soru 10kolay

Write static void selectionSort(int[] a).

Cevabı göster
For i = 0..n-2: find index of minimum in a[i..n-1]; swap with a[i].

static void selectionSort(int[] a) {
    for (int i = 0; i < a.length - 1; i++) {
        int min = i;
        for (int j = i + 1; j < a.length; j++)
            if (a[j] < a[min]) min = j;
        int t = a[i];
        a[i] = a[min];
        a[min] = t;
    }
}
En fazla n − 1 takas yapar; takası pahalı olan veriler (büyük kayıtlar) için bu bir avantaj. {38, 12, 45, 7, 29, 16} üzerinde 3 gerçek takas yapıldı.

Soru 11zor

Starting from {4, 2, 6, 1, 3}, an algorithm produced [2, 4, 6, 1, 3] after pass 1 and [2, 4, 6, 1, 3] after pass 2. Another produced [1, 2, 6, 4, 3] after pass 1. A third produced [2, 4, 1, 3, 6] after pass 1. Identify each.

Cevabı göster
first: insertion, second: selection, third: bubble

Insertion: baştaki k + 1 eleman kendi aralarında sıralı ama geri kalan dokunulmamış (1, 3 yerinde duruyor). Selection: en küçük 1 başa geldi, 4 ile takas edilen yerde (indeks 3) 4 duruyor. Bubble: en büyük 6 sona gitti ve diğerleri birer konum kaydı. İpucu: başta nihai minimum → selection, sonda nihai maksimum → bubble, başta yerel sıralı ve kalanı aynı → insertion.

Soru 12kolay

Give the best, average and worst case time complexity of bubble sort (with flag), selection sort and insertion sort.

Cevabı göster
bubble O(n)/O(n^2)/O(n^2); selection O(n^2) in all cases; insertion O(n)/O(n^2)/O(n^2)

Üçü de yerinde (in-place, O(1) ek bellek). Rastgele dizide program karşılaştırmaları saydı: n = 1000 → 2000 → 4000 için selection 499 500 → 1 999 000 → 7 998 000 (x4), insertion yaklaşık yarısı (245 712 → 985 303 → 3 980 580), yine x4. Pratikte en hızlısı insertion; küçük ve neredeyse sıralı dizilerde çok iyidir.

Doğrulama: Üç algoritma verify/SEN2211/W13.java içinde her geçişten sonra diziyi yazdıracak şekilde JDK ile çalıştırıldı (java W13.java). Geçiş izleri, karşılaştırma/takas/kaydırma sayıları ve ters çevrim (inversion) sayıları programın sayaçlarından alındı. Kararlılık, eşit anahtarlı etiketli kayıtlarla denendi; büyüme n = 1000, 2000, 4000 rastgele dizide karşılaştırma sayılarıyla ölçüldü.

Deftere not kartı

BUBBLE: komşuları karşılaştır, büyükse takas; her geçişte EN BÜYÜK SONA yerleşir j < n - pass; takas olmazsa DUR (bayrak) → sıralıda O(n) takas sayısı = ters çevrim (inversion) sayısı; STABLE SELECTION: kalan kısmın MİNİMUMUNU bul, a[i] ile takas; baştaki kısım NİHAİ karşılaştırma HER ZAMAN n(n-1)/2; en fazla n-1 takas; NOT STABLE (uzak takas) INSERTION: a[i]'yi (key) sakla, soldaki büyükleri sağa kaydır, boşluğa koy baştaki kısım sıralı ama nihai DEĞİL; sıralıda n-1 karşılaştırma O(n); ters sıralıda n(n-1)/2 kaydırma sayısı = ters çevrim sayısı; STABLE (a[j] > key, >= DEĞİL) Üçü de: in-place O(1) bellek, en kötü O(n²) Geçiş tanıma: sonda nihai max → bubble | başta nihai min → selection | baş yerel sıralı, son dokunulmamış → insertion n=6: tam tarama 5+4+3+2+1 = 15 karşılaştırma