Bölüm 19: Temel Sıralama Algoritmaları
Çoktan Seçmeli · Sıralama Kavramları
Soru 1: Süslü Parantezli SWAP
SWAP makrosu do { … } while (0) yerine yalnız süslü parantezle tanımlanmıştır. Program derlenip çalıştırılırsa ne olur?
#define SWAP(A, B) { int t = A; A = B; B = t; } int main(void) { int a = 2, b = 1; if (a > b) SWAP(a, b); else printf("sirali\n"); printf("%d %d\n", a, b); return 0; }
B: SWAP(a, b); açılınca { … }; olur. Bloktan sonraki noktalı virgül boş bir deyimdir; if bu blokla biter ve else yetim kalır (zig cc: "expected expression"). do { … } while (0) tek bir deyim gibi davranır ve noktalı virgülü yutar.
Çoktan Seçmeli · Sıralama Kavramları
Soru 2: Kararlı Sıralama
Tutanaklar (Ali, 70), (Can, 85), (Ece, 70), (Banu, 85), (Deniz, 60) sırasıyla geliyor. Nota göre artan sırada kararlı bir sıralamanın çıktısı hangisidir?
C: Kararlı sıralamada eşit anahtarlı tutanaklar girdideki göreli sıralarını korur: Ali Ece'den, Can Banu'dan önce gelir. A ve D 70'leri, B ve D 85'leri ters çevirir. Eklemeli sıralamayla (a[j] > v) denenen program da C'yi verdi.
Adım Adım Çalıştırma · Seçimli Sıralama
Soru 3: Seçimli Sıralama Kararlı mı?
selection(a, 0, 4) çağrılıyor; a = [3a, 5, 3b, 1, 2] (3a ve 3b aynı değer, etiketler yalnız sırayı izlemek için). Eşit öğelerin sırası korunur mu?
İki 3 değeri etiketlendi: 3a önde, 3b arkada. Kararlı bir sıralama bu sırayı korumalıdır.
Tur i = 0: a[0..4] taranır, en küçük a[3] = 1.
SWAP(a[0], a[3]): 1 öne geldi; 3a uzaktaki 3. konuma atlayarak 3b'nin arkasına geçti.
Tur i = 1: a[1..4] taranır, en küçük a[4] = 2.
SWAP(a[1], a[4]): 2 öne geldi, 5 4. konuma atladı.
Tur i = 2: a[2..4] taranır, en küçük a[2] = 3b.
min = i: takas kendisiyle yapılır, dizi değişmez.
Tur i = 3: a[3..4] taranır, en küçük a[3] = 3a.
min = i: takas kendisiyle yapılır, dizi değişmez.
Sonuç sıralı ama 3b, 3a'nın önünde: uzak takas yüzünden seçimli sıralama kararlı değildir.
void selection(int a[], int L, int R) { for (int i = L; i < R; i++) { int min = i; for (int j = i + 1; j <= R; j++) if (kucuk(a[j], a[min])) min = j; SWAP(a[i], a[min]); } }
Çoktan Seçmeli · Seçimli Sıralama
Soru 4: Seçimlide Sayım
n = 8 öğeli, zaten sıralı bir dizide selection kaç karşılaştırma ve kaç SWAP çağrısı yapar?
A: İç döngü dizinin sıralı olduğunu bilmez: 7 + 6 + … + 1 = 28 karşılaştırma. Her dış turun sonunda SWAP çağrılır; min = i olduğu için öğe kendisiyle takaslanır: 7 çağrı, gerçek yer değişikliği 0. Karşılaştırma sayısı girdiden bağımsızdır.
Hata Bulma · Seçimli Sıralama
Soru 5: En Küçük Değeri Tutmak
Bu seçimli sıralamada min indis yerine değeri tutuyor. a = [4, 2, 5, 1] için selection(a, 0, 3) sonrası dizi nedir? Hatayı düzeltin.
void selection(int a[], int L, int R) { for (int i = L; i < R; i++) { int min = a[i]; for (int j = i + 1; j <= R; j++) if (a[j] < min) min = a[j]; SWAP(a[i], min); } }
Cevabı göster
Sonuç [1, 1, 1, 1]:
- i = 0: min = 1.
SWAP(a[0], min)a[0]'a 1 yazar, 4 ise yerelmin'e gider ve kaybolur: [1, 2, 5, 1]. - i = 1: en küçük yine 1 (a[3]) → [1, 1, 5, 1]. i = 2: → [1, 1, 1, 1].
En küçük öğe a[i]'ye kopyalanır ama bulunduğu hücreye a[i]'nin eski değeri yazılmaz; değerler çoğalır, 4, 2 ve 5 silinir. Takas için indis gerekir: int min = i;, if (a[j] < a[min]) min = j;, SWAP(a[i], a[min]);
Çıktı Sorusu · Eklemeli Sıralama
Soru 6: Karşılaştırma ve Kaydırma
Eklemeli sıralamaya sayaçlar eklenmiştir (virgül işleci önce sayacı artırır, sonra karşılaştırır). Program ne yazdırır?
long karsil = 0, kaydir = 0; void insertion_say(int a[], int L, int R) { for (int i = L + 1; i <= R; i++) { int v = a[i], j = i - 1; while (j >= L && (karsil++, a[j] > v)) { a[j + 1] = a[j]; j--; kaydir++; } a[j + 1] = v; } } /* main: int a[] = {3, 7, 4, 1, 5}; insertion_say(a, 0, 4); printf("%ld %ld", karsil, kaydir); */
Cevabı göster
Çıktı: 8 5
- i = 1 (7): 3 > 7 yanlış → 1 karşılaştırma.
- i = 2 (4): 7 kaydı, 3 durdurdu → 2 karşılaştırma, 1 kaydırma.
- i = 3 (1): 7, 4, 3 kaydı; j = −1 olunca
j >= Lyanlış, a[j] hiç sınanmaz → 3 karşılaştırma, 3 kaydırma. - i = 4 (5): 7 kaydı, 4 durdurdu → 2 karşılaştırma, 1 kaydırma.
Kaydırma sayısı evrik sayısına eşittir: (3,1), (7,4), (7,1), (7,5), (4,1) = 5.
Çoktan Seçmeli · Eklemeli Sıralama
Soru 7: j >= 0 Sınırı
İç döngü koşulu j >= L yerine j >= 0 yazılmıştır. a = [9, 8, 5, 3, 4] için insertion(a, 2, 4) sonrası dizi nedir?
while (j >= 0 && a[j] > v) {
a[j + 1] = a[j];
j--;
}
a[j + 1] = v;D: Yalnız a[2..4] sıralanmalıdır. 3 yerleştirilirken 5, 8 ve 9 sağa kaydırılır: [3, 9, 8, 5, 4]. 4 ise 9, 8, 5'i kaydırıp 3'ün arkasında durur: [3, 4, 9, 8, 5]. Alt dizinin dışı bozuldu, alt dizi de sıralanmadı. Doğru sınırla sonuç A olur.
Çoktan Seçmeli · Kabarcık Sıralaması
Soru 8: Kabarcıkta Takas
bubble yordamı [3, 5, 1, 4, 2] dizisini sıralarken kaç takas yapar?
B: Komşu takası tam bir evriği giderir; takas sayısı evrik sayısına eşittir: (3,1), (3,2), (5,1), (5,4), (5,2), (4,2) = 6. Karşılaştırma ise erken durma olmadan her girdide n(n − 1)/2 = 10'dur (C ile sayıldı).
Adım Adım Çalıştırma · Sayarak Sıralama
Soru 9: Sayarak Sıralamada Kararlılık
counting_sort a = [2, 0, 2, 1, 0, 2], r = 5, k = 2 ile çağrılıyor (etiketler eşitleri izlemek için). c ve b dizileri nasıl dolar?
L1–L2: c[x] = x değerinin kaç kez geçtiği: iki 0, bir 1, üç 2.
L3 birikimli toplam: c[x] = x'ten küçük ya da eşit öğe sayısı. 2'ler b[3..5]'e gidecek.
L4 sağdan başlar: a[5] = 2c → b[5] (2'lerin en sağı); c[2] = 5.
L4: a[4] = 0b → b[1]; c[0] = 1 olur.
L4: a[3] = 1 → b[2]; c[1] = 2 olur.
L4: a[2] = 2b → b[4]; c[2] = 4 olur.
L4: a[1] = 0a → b[0]; c[0] = 0 olur.
L4: a[0] = 2a → b[3]; c[2] = 3 olur.
Sonuç [0a, 0b, 1, 2a, 2b, 2c]: eşitlerin sırası korundu. Sağdan gezildiği için her değerin son kopyası en sağdaki boş yere yazılır.
/* L1 */ for (int i = 0; i <= k; i++) c[i] = 0; /* L2 */ for (int j = 0; j <= r; j++) c[a[j]]++; /* L3 */ for (int i = 1; i <= k; i++) c[i] += c[i - 1]; /* L4 */ for (int j = r; j >= 0; j--) { b[c[a[j]] - 1] = a[j]; c[a[j]]--; }
Çoktan Seçmeli · Sayarak Sıralama
Soru 10: L4 Soldan Sağa
counting_sort'ta L4 döngüsü for (int j = 0; j <= r; j++) olarak yazılırsa ne olur?
A: c[x] hâlâ x'lerin bloğunun son konumunu gösterir. Soldan gezilince x'in ilk kopyası bloğun en sağına, sonuncusu en soluna yazılır: değerler doğru, eşitler ters. Sayılar için fark görünmez, ama basamağa göre sıralamada kararlılık gerekir ve sonuç bozulur.
Kod Yazma · Sayarak Sıralama
Soru 11: Negatif Değerlerle Sayarak
Değerleri [lo, hi] aralığında (negatif olabilir) n tamsayıyı kararlı biçimde sıralayan int sayarak_aralik(const int a[], int b[], int n, int lo, int hi) yordamını yazın. Sayaç dizisi heap'te ayrılsın; hata durumunda −1 dönsün.
Cevabı göster
int sayarak_aralik(const int a[], int b[], int n, int lo, int hi) { if (hi < lo) return -1; int k = hi - lo + 1; int *c = calloc(k, sizeof *c); /* sıfırlı */ if (c == NULL) return -1; for (int j = 0; j < n; j++) c[a[j] - lo]++; for (int i = 1; i < k; i++) c[i] += c[i - 1]; for (int j = n - 1; j >= 0; j--) /* kararlı */ b[--c[a[j] - lo]] = a[j]; free(c); return 0; }
Değer x, c[x − lo] hücresinde sayılır; böylece −2 indis 0'a düşer. a = [3, −2, 0, 3, −1, −2], lo = −2, hi = 3 için b = [−2, −2, −1, 0, 3, 3]. Zaman ve bellek O(n + k).
Adım Adım Çalıştırma · Shell ve Kova Sıralama
Soru 12: Shell ile Daha Az Kaydırma
shell_sort [5, 1, 6, 2, 4, 3] ile çağrılıyor (h = 3, 1). Hangi adımlarda kaydırma olur? Toplam kaydırma, düz eklemeli sıralamanınkiyle karşılaştırıldığında nasıldır?
Evrik sayısı 8: düz eklemeli sıralama 8 kaydırma yapardı.
Aralık h = 3: (a[0], a[3]), (a[1], a[4]), (a[2], a[5]) çiftleri ayrı ayrı eklemeli sıralanır.
i = 3: v = 2, 1 kez 3 geri kaydırıldı → a[0] = 2. Toplam kaydırma 1.
i = 5: v = 3, 1 kez 3 geri kaydırıldı → a[2] = 3. Toplam kaydırma 2.
Son tur h = 1: sıradan eklemeli sıralama, ama dizi artık neredeyse sıralı.
i = 1: v = 1, 1 kez 1 geri kaydırıldı → a[0] = 1. Toplam kaydırma 3.
i = 4: v = 4, 1 kez 1 geri kaydırıldı → a[3] = 4. Toplam kaydırma 4.
h = 0: bitti. Toplam 4 kaydırma; h = 3 turundaki iki uzak kaydırma 8 evrikten 6'sını birden giderdi.
void shell_sort(int a[], int n) { for (int h = n / 2; h > 0; h /= 2) for (int i = h; i < n; i++) { int v = a[i], j = i; while (j >= h && a[j - h] > v) { a[j] = a[j - h]; j -= h; } a[j] = v; } }
Klasik Soru · Shell ve Kova Sıralama
Soru 13: Kovalar
bucket_sort n = 5 ve a = [0,42, 0,32, 0,23, 0,52, 0,25] ile çağrılıyor. Her sayı hangi kovaya düşer? Dağıtım bittiğinde kovaların listeleri nedir? Bu girdi kova sıralaması için iyi midir?
Cevabı göster
Kova numarası ⌊5x⌋: 0,42 → 2, 0,32 → 1, 0,23 → 1, 0,52 → 2, 0,25 → 1.
| kova | 0 | 1 | 2 | 3 | 4 |
|---|---|---|---|---|---|
| liste | — | 0,23 → 0,25 → 0,32 | 0,42 → 0,52 | — | — |
Her sayı kendi listesine sıralı eklenir (0,23, 0,32'nin önüne; 0,25 ikisinin arasına). Kovalar sırayla toplanınca [0,23, 0,25, 0,32, 0,42, 0,52].
Sayılar [0,2; 0,6) aralığında toplandığı için beş kovanın üçü boş, biri üç öğeli kaldı. Düzgün dağılım varsayımı zayıfladıkça kova içi eklemeli sıralamanın payı büyür; en kötü durumda O(n²).
Çoktan Seçmeli · Optimal Sıralama Zamanı
Soru 14: Altı Öğede Alt Sınır
6 farklı öğeyi sıralayan karşılaştırmalı bir algoritma en kötü durumda en az kaç karşılaştırma yapmak zorundadır?
C: Karar ağacının en az 6! = 720 yaprağı vardır. 2⁹ = 512 < 720 ≤ 1024 = 2¹⁰ olduğundan yükseklik en az ⌈lg 720⌉ = 10. Seçimli sıralama her girdide 15 karşılaştırma yapar; alt sınırın 5 fazlası.
Kod Yazma · Özet
Soru 15: Tutanakları Kararlı Sıralamak
typedef struct { char ad[12]; int not_; } ogrenci; tutanaklarını nota göre artan sırada, kararlı ve yerinde sıralayan void ogr_sirala(ogrenci a[], int n) yordamını eklemeli sıralamayla yazın.
Cevabı göster
void ogr_sirala(ogrenci a[], int n) { for (int i = 1; i < n; i++) { ogrenci v = a[i]; /* tutanak kopyası */ int j = i - 1; while (j >= 0 && a[j].not_ > v.not_) { a[j + 1] = a[j]; /* struct ataması */ j--; } a[j + 1] = v; } }
Kararlılığı katı > sağlar: eşit notta kaydırma durur, öğe eşitinin arkasında kalır. >= yazılsaydı eşitler yer değiştirirdi. Struct ataması bütün alanları kopyalar; büyük tutanaklarda indis ya da işaretçi dizisi sıralamak daha ucuzdur. (Ali, 70), (Can, 85), (Ece, 70), (Banu, 85), (Deniz, 60) girdisi Deniz, Ali, Ece, Can, Banu verir.
Çoktan Seçmeli · Özet
Soru 16: Hangi Algoritma?
100 000 tutanaklı, neredeyse sıralı (yalnız birkaç tutanak yerinde değil) bir dizi kararlı biçimde sıralanacak; ek bellek kullanılmayacak. Hangisi en uygundur?
D: Eklemeli sıralama kararlı ve yerindedir; neredeyse sıralı veride kaydırma sayısı evrik sayısı kadar, yani çok azdır. Seçimli girdiye kördür (≈ n²/2 karşılaştırma) ve kararsızdır; Shell kararsızdır; sayarak sıralama ek bellek ister ve yalnız küçük tamsayı aralığında anlamlıdır.