Birleştirmeli Sıralama: Böl, Sırala, Birleştir
Birleştirmeli sıralamayı özyinelemeli olarak uygulayın, böl ve yönet ağacını izleyin ve her durumda neden O(n log n) garantisi verdiğini açıklayın.
Birleştirmeli Sıralama: Böl, Sırala, Birleştir, CoddyKit'te ücretsiz bir DSA Interview Prep dersidir. Bu, 4 dersinin 2. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, DSA Interview Prep öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. DSA Interview Prep kursu toplamda 4 dersten oluşur.
Böl ve Yönet Sezgisi
Birleştirmeli sıralama, klasik bir böl ve yönet algoritmasıdır: diziyi ikiye split edin, her yarıyı özyinelemeli olarak sort edin, ardından iki sıralı yarıyı tek bir sıralı sonuçta merge edin. Temel gözlem, iki sıralı diziyi birleştirmenin O(n) olmasıdır; bu, sıfırdan sıralamaktan çok daha ucuzdur. Bu parçalama, log n düzeyden oluşan bir özyineleme ağacı meydana getirir; her düzeyde O(n) birleştirme işi gerektiği için karşılaştırmalı sıralama için en iyi sınır olan O(n log n) elde edilir.
# High-level merge sort structure
def merge_sort(arr):
# Base case: 0 or 1 element already sorted
if len(arr) <= 1:
return arr
# Divide
mid = len(arr) // 2
left = merge_sort(arr[:mid]) # sort left half
right = merge_sort(arr[mid:]) # sort right half
# Conquer (merge)
return merge(left, right)
print(merge_sort([38, 27, 43, 3, 9, 82, 10]))
# [3, 9, 10, 27, 38, 43, 82]Birleştirme Adımının Açıklaması
İki sıralı diziyi birleştirirken her yarı için birer tane olmak üzere iki işaretçi tutun. Öndeki öğeleri karşılaştırın; daha küçük olanı çıktıya copy edin ve ilgili işaretçiyi ilerletin. Yarılardan biri tükendiğinde diğer yarının kalanını doğrudan kopyalayın. Bu işlem O(n) zamanda çalışır ve çıktı dizisi için O(n) alan kullanır. Merge adımı, birleştirmeli sıralamanın algoritmik kalbidir; bu adımı derinlemesine anlayın.
def merge(left, right):
result = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]: # <= preserves stability
result.append(left[i])
i += 1
else:
result.append(right[j])
j += 1
# Append remaining elements
result.extend(left[i:])
result.extend(right[j:])
return result
print(merge([1,3,5,7], [2,4,6,8]))
# [1, 2, 3, 4, 5, 6, 7, 8]Birleştirmeli Sıralamanın Eksiksiz Uygulaması
Parçalama ve birleştirmeyi bir araya getirme: özyinelemeli çağrılar, geriye tek tek öğeler kalana (bunlar doğası gereği sıralıdır) kadar problemi ikiye böler; ardından birleştirme çağrıları bunları yeniden bir araya getirir. Özyineleme ağacının her düzeyi, birden çok birleştirmeye dağıtılmış olsa da toplamda aynı n öğeyi birleştirir. Özyineleme derinliği log₂(n) olduğundan toplam süre O(n log n) olur; birleştirme çıktısı dizileri için O(n) ek alanın yanı sıra çağrı yığını derinliği için O(log n) alan kullanılır.
def merge_sort_full(arr):
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = merge_sort_full(arr[:mid])
right = merge_sort_full(arr[mid:])
# Merge the two sorted halves
merged = []
i = j = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]: merged.append(left[i]); i += 1
else: merged.append(right[j]); j += 1
merged.extend(left[i:] + right[j:])
return merged
print(merge_sort_full([5,2,4,6,1,3,2,6]))
# [1, 2, 2, 3, 4, 5, 6, 6]Birleştirmeli Sıralamanın Özyineleme Ağacı
n=8 için birleştirmeli sıralamanın özyineleme ağacını görselleştirelim: 0. düzeyde 8 öğeli bir dizi; 1. düzeyde 4 öğeli iki dizi; 2. düzeyde 2 öğeli dört dizi; 3. düzeyde ise tek öğelerden oluşan sekiz dizi (temel durumlar) bulunur. Yukarı çıkarken 3. düzey → 2. düzey, toplam 8 öğeyi; 2. düzey → 1. düzey, toplam 8 öğeyi; 1. düzey → 0. düzey de toplam 8 öğeyi birleştirir. Bu, 3 düzey × 8 öğe = 24 işlem ≈ 8 × log₂(8) = 24 demektir. Bu da O(n log n) sonucunu doğrular.
# Trace the tree depth
level_work = []
def merge_sort_traced(arr, depth=0):
if depth >= len(level_work):
level_work.append(0)
if len(arr) <= 1:
return arr
mid = len(arr) // 2
left = merge_sort_traced(arr[:mid], depth+1)
right = merge_sort_traced(arr[mid:], depth+1)
level_work[depth] += len(arr) # track merge work
merged = sorted(left + right) # simplified merge
return merged
merge_sort_traced(list(range(8, 0, -1)))
for d, work in enumerate(level_work):
print(f'Level {d}: {work} elements merged')Yerinde Birleştirmeli Sıralama
Standart özyinelemeli birleştirmeli sıralama, birleştirme çıktısı için O(n) ek alan ayırır. Yerinde birleştirmeli sıralama mümkündür; ancak karmaşıktır ve sabit çarpanları yüksektir — mülakatlarda nadiren sorulur. Mülakatlarda sık sorulan devam sorusu şudur: 'Birleştirmeli sıralamayı O(1) ek alanla yapabilir misiniz?' Doğru yanıt şöyledir: 'Teorik olarak evet; ancak pratik uygulamalar ya O(n) alandan ödün verir ya da karmaşıklığı artırır. Python'ın Timsort algoritması birleştirme için O(n) alan kullanır.'
# Bottom-up merge sort: iterative, avoids recursion stack
def merge_sort_bottomup(arr):
n = len(arr)
width = 1
while width < n:
for i in range(0, n, 2 * width):
left = arr[i:i+width]
right = arr[i+width:i+2*width]
# Merge and put back
merged = []
a, b = 0, 0
while a < len(left) and b < len(right):
if left[a] <= right[b]: merged.append(left[a]); a+=1
else: merged.append(right[b]); b+=1
merged += left[a:] + right[b:]
arr[i:i+len(merged)] = merged
width *= 2
return arr
print(merge_sort_bottomup([5,2,4,6,1,3]))
# [1, 2, 3, 4, 5, 6]Birleştirmeli Sıralama Kararlıdır
Birleştirmeli sıralama kararlıdır: sol yarıdaki eşit öğeler, birleştirilmiş çıktıda her zaman sağ yarıdaki eşit öğelerden önce görünür. Bu, sol öğeyi tercih ederken <= ( < değil) kullanılmasının garantisidir. Kararlılık, çok anahtarlı sıralama için önemlidir. Python'ın yerleşik sorted() ve list.sort() işlevleri, kararlı olan ve O(n log n) sürede çalışan Timsort algoritmasını kullanır; bu nedenle tüm üretim kodları için güvenli tercihtir.
# Demonstrating stability: sort (value, original_index) pairs
items = [(3,'A'), (1,'B'), (3,'C'), (2,'D')]
# Sort by value only
result = merge_sort_full(items) # won't work directly
# Use Python's stable sort:
result = sorted(items, key=lambda x: x[0])
print(result)
# [(1,'B'),(2,'D'),(3,'A'),(3,'C')]
# 'A' comes before 'C' for value=3 (stable order)K Sıralı Diziyi Birleştirme
Toplam n öğe içeren k sıralı dizi, çiftleri art arda birleştirerek (bir turnuva eşleşmesi gibi) O(n log k) sürede birleştirilebilir. Her birleştirme düzeyi n öğeyi işler ve log k düzey bulunur. Alternatif olarak, k boyutunda bir minimum yığını kullanabilirsiniz: her diziden kalan en küçük öğeyi yığına ekleyin, minimumu çıkarın ve o dizideki bir sonraki öğeyi ekleyin. Yığın yaklaşımı da O(n log k) sürededir; ancak k çok büyük olduğunda bellek açısından daha verimlidir.
import heapq
def merge_k_sorted(arrays):
result = []
heap = []
# Push first element from each array with array index
for i, arr in enumerate(arrays):
if arr:
heapq.heappush(heap, (arr[0], i, 0))
while heap:
val, arr_i, elem_i = heapq.heappop(heap)
result.append(val)
if elem_i + 1 < len(arrays[arr_i]):
next_val = arrays[arr_i][elem_i + 1]
heapq.heappush(heap, (next_val, arr_i, elem_i+1))
return result
arrs = [[1,4,7],[2,5,8],[3,6,9]]
print(merge_k_sorted(arrs)) # [1,2,3,4,5,6,7,8,9]Birleştirmeli Sıralamayla Terslikleri Sayma
O(n log n) sürede terslikleri (a[i] > a[j] ve i < j olan çiftleri) saymak için değiştirilmiş birleştirmeli sıralama kullanılır. Birleştirme adımı sırasında sağ alt dizideki bir öğe, sol alt dizideki bir öğeden küçük olduğunda, sol alt dizide kalan her öğeyle bir terslik oluşturur. O anda sayaca len(left) - i değerini ekleyin.
def count_inversions(arr):
if len(arr) <= 1:
return arr, 0
mid = len(arr) // 2
left, l_inv = count_inversions(arr[:mid])
right, r_inv = count_inversions(arr[mid:])
merged = []
inversions = l_inv + r_inv
i = j = 0
while i < len(left) and j < len(right):
if left[i] <= right[j]:
merged.append(left[i]); i += 1
else:
merged.append(right[j]); j += 1
inversions += len(left) - i # all remaining left elements > right[j]
merged.extend(left[i:] + right[j:])
return merged, inversions
_, inv = count_inversions([3, 1, 2])
print(inv) # 2: (3,1) and (3,2)Birleştirmeli Sıralama ve Hızlı Sıralama
Birleştirmeli sıralama tüm durumlarda O(n log n) süresini garanti eder, kararlıdır ve bağlı listeler ile harici sıralama için daha iyi tercihtir. Hızlı sıralamanın ortalama durumu O(n log n), en kötü durumu ise O(n²) süresindedir; yerinde çalışır (O(log n) yığın alanı kullanır) ve dizilerdeki önbellek verimliliği sayesinde pratikte çoğu zaman daha hızlıdır. Python'ın yerleşik sıralaması Timsort'u (birleştirmeli sıralama çeşidi) kullanır — her zaman doğru varsayılan tercihtir.
# Head-to-head complexity comparison:
# Algorithm | Best | Avg | Worst | Space | Stable
# Bubble sort | O(n) | O(n^2) | O(n^2) | O(1) | Yes
# Insertion sort| O(n) | O(n^2) | O(n^2) | O(1) | Yes
# Merge sort | O(nlogn)| O(nlogn)| O(nlogn)| O(n) | Yes
# Quick sort | O(nlogn)| O(nlogn)| O(n^2) | O(logn)| No
# Heap sort | O(nlogn)| O(nlogn)| O(nlogn)| O(1) | No
print('Merge sort: stable, O(n log n) guaranteed, O(n) space')Harici Sıralama: Büyük Ölçekte Birleştirmeli Sıralama
Birleştirmeli sıralama, harici sıralamanın (RAM'e sığmayacak kadar büyük verileri sıralamanın) temelindeki algoritmadır. Veriler parçalar hâlinde okunur, her parça bellekte sıralanır ve parçalar diskten birleştirilir. Birleştirme adımı, her sıralı parçadan birer öğe okuyarak aynı anda bellekte yalnızca O(k) öğe (her parça için bir öğe) tutar. Bu nedenle birleştirmeli sıralama veritabanlarında, Hadoop MapReduce'da ve klasik teyp sıralama algoritmalarında kullanılır.
# Simulated external sort: sort in chunks then merge
def external_sort(data, chunk_size):
chunks = []
for i in range(0, len(data), chunk_size):
chunk = sorted(data[i:i+chunk_size]) # sort in-memory
chunks.append(chunk)
print(f'Created {len(chunks)} sorted chunks')
# Merge all chunks
import heapq
heap = [(c[0], i, 0) for i, c in enumerate(chunks) if c]
heapq.heapify(heap)
result = []
while heap:
val, ci, ei = heapq.heappop(heap)
result.append(val)
if ei + 1 < len(chunks[ci]):
heapq.heappush(heap, (chunks[ci][ei+1], ci, ei+1))
return result
print(external_sort(list(range(20,0,-1)), 5)[:10])Birleştirmeli Sıralama Özeti ve Mülakat İpuçları
Mülakatlarda, birleştirmeli sıralamayı temiz bir şekilde uygulamak; özyinelemeyi, birleştirme adımını ve böl ve yönet yaklaşımını anladığınızı gösterir. Yaygın devam soruları:
- Neden O(n log n), O(n²) değil? (log n düzey × düzey başına n iş)
- Kararlı mı? (Evet, birleştirmede <= kullanın)
- Ne kadar alan kullanır? (O(n) ek alan + O(log n) yığın)
- İteratif olarak yapabilir misiniz? (Evet, alttan üste birleştirmeli sıralama)
- Bağlı listede nasıl kullanırsınız? (Diziden daha kolaydır — O(n) dilim maliyeti yoktur; orta noktayı bulmak için yavaş ve hızlı işaretçileri kullanın)
# One-shot merge sort for interview clarity:
def ms(a):
if len(a) <= 1: return a
m = len(a) // 2
l, r, res, i, j = ms(a[:m]), ms(a[m:]), [], 0, 0
while i < len(l) and j < len(r):
if l[i] <= r[j]: res.append(l[i]); i+=1
else: res.append(r[j]); j+=1
return res + l[i:] + r[j:]
print(ms([5,2,4,6,1,3])) # [1,2,3,4,5,6]Hızlı Kontrol
Bu dersteki Veri Yapıları & Algoritmalar — Kodlama Mülakatı Hazırlığı kavramlarını ne kadar anladığınızı sınayın.
Ders Özeti
Bu derste şunları öğrendiniz: birleştirmeli sıralama diziyi orta noktadan böler, her yarıyı özyinelemeli olarak sıralar ve sıralanmış iki yarıyı O(n) içinde birleştirir; böylece log n özyineleme düzeyi boyunca toplam O(n log n) çalışma süresi elde edilir, birleştirme adımı, eşitlik durumlarında sol öğeyi almak için <= kullanır ve kararlılığı garanti eder ve birleştirmeli sıralama, bağlı listeler, harici sıralama ve kararlılığın gerekli olduğu durumlar için tercih edilen algoritmadır; alan sınırlı olduğunda ise bellekteki diziler için hızlı sıralama tercih edilir. Sırada hızlı sıralamayı uygulayıp pivot seçimi stratejilerini inceleyeceğiz.
Sıkça Sorulan Sorular
“Birleştirmeli Sıralama: Böl, Sırala, Birleştir” dersi ücretsiz mi?
Evet — “Birleştirmeli Sıralama: Böl, Sırala, Birleştir” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve DSA Interview Prep kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. DSA Interview Prep kursu toplamda 4 dersten oluşur.
“Birleştirmeli Sıralama: Böl, Sırala, Birleştir” dersinde ne öğreneceğim?
Birleştirmeli sıralamayı özyinelemeli olarak uygulayın, böl ve yönet ağacını izleyin ve her durumda neden O(n log n) garantisi verdiğini açıklayın. DSA Interview Prep ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.
DSA Interview Prep öğrenmeye başlamak için deneyim gerekli mi?
Önceden deneyim gerekmez. CoddyKit'te DSA Interview Prep, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 2. dersidir.
“Birleştirmeli Sıralama: Böl, Sırala, Birleştir” dersi ne kadar sürer?
Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.
Bu DSA Interview Prep dersinde kod yazıp çalıştırabilir miyim?
Evet. Her DSA Interview Prep dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.
Bu kursun tüm dersleri
- Kabarcık Sıralaması ve Eklemeli Sıralama
- Birleştirmeli Sıralama: Böl, Sırala, Birleştir
- Hızlı Sıralama ve Dönüm Noktası Seçimi
- Karşılaştırmasız Sıralamalar ve Python’un sort() İşlevi