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.
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:
- Bubble: her geçişte en büyük eleman sona “kabarcıklanır”.
- Selection: her geçişte kalan kısmın en küçüğü başa seçilir.
- Insertion: her geçişte bir sonraki eleman, soldaki sıralı kısımda doğru yerine sokulur.
- “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 . 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 :
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:
| Algoritma | Geç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ı) | Selection | Insertion | |
|---|---|---|---|
| En iyi | O(n) | O(n²) | O(n) |
| Ortalama | O(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 bellek | O(1) | O(1) | O(1) |
| Kararlı | evet | hayır | evet |
| Uyarlanabilir | evet | hayır | evet |
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 < n | j < 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 saklamamak | Kaydırma a[i]‘nin üstüne yazar; int key = a[i]; |
Insertion’da a[j] >= key | Kararlılığı bozar; > |
| Selection sıralı dizide hızlıdır | Her zaman n(n−1)/2 karşılaştırma |
| Selection kararlıdır | Uzak takas eşitlerin sırasını bozabilir |
| Insertion’ın baştaki kısmı nihai | Sadece 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ç.
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
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].
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
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.
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
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.
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
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.
How many comparisons does selection sort make on an array of 6 elements? Does it depend on the input order?
Cevabı göster
Geçiş i'de kalan n − i eleman taranır: 5 + 4 + 3 + 2 + 1 = 15 = . 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).
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
İ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ı.
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
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.
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 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.
Write static void insertionSort(int[] a).
Cevabı göster
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.Write static void selectionSort(int[] a).
Cevabı göster
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ı.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
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.
Give the best, average and worst case time complexity of bubble sort (with flag), selection sort and insertion sort.
Cevabı göster
Üçü 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ü.