Takip et

Giriş: Merge Sort Nedir?

Giriş: Merge Sort Nedir? Sıralama algoritmaları, bilgisayar bilimlerinin ve yazılım geliştirmenin temel taşlarından biridir. Verileri belirl

Giriş: Merge Sort Nedir?

Sıralama algoritmaları, bilgisayar bilimlerinin ve yazılım geliştirmenin temel taşlarından biridir. Verileri belirli bir düzene sokmak, arama işlemlerini hızlandırmak, raporlama ve analiz yeteneklerini artırmak için kritik öneme sahiptirler. Birçok sıralama algoritması arasında Merge Sort (Birleştirmeli Sıralama), “böl ve yönet” (divide and conquer) paradigmalarını en zarif şekilde uygulayan, performansı garanti eden ve kararlı özelliklere sahip güçlü bir algoritmadır.

Merge Sort, 1945 yılında John von Neumann tarafından icat edilmiştir. Temel prensibi, sıralanacak diziyi sürekli olarak daha küçük alt dizilere bölmek, bu alt dizileri bağımsız olarak sıralamak ve ardından sıralı alt dizileri birleştirerek nihai sıralı diziyi elde etmektir. Bu yaklaşım, özellikle büyük veri setleri üzerinde tutarlı ve öngörülebilir bir performans sergilemesiyle bilinir.

Merge Sort’un Çalışma Prensibi ve Adımları

Merge Sort algoritması, iki ana aşamadan oluşur: Bölme (Divide) ve Birleştirme (Merge/Conquer). Bu aşamalar özyinelemeli (recursive) bir yapı içinde çalışır.

1. Bölme (Divide) Aşaması

Bu aşamada, sıralanacak ana dizi, orta noktasından ikiye bölünür. Bu bölme işlemi, her bir alt dizide yalnızca bir eleman kalana kadar özyinelemeli olarak devam eder. Tek bir elemandan oluşan bir dizi, tanım gereği zaten sıralıdır. Bu aşamada herhangi bir sıralama işlemi yapılmaz, sadece dizi parçalanır.

Örnek bir dizi üzerinden düşünelim: [38, 27, 43, 3, 9, 82, 10]

  • Dizi ikiye bölünür: [38, 27, 43, 3] ve [9, 82, 10]
  • Sol alt dizi tekrar bölünür: [38, 27] ve [43, 3]
  • Sağ alt dizi tekrar bölünür: [9, 82] ve [10]
  • Bu işlem, her alt dizide tek bir eleman kalana kadar devam eder: [38], [27], [43], [3], [9], [82], [10]

2. Birleştirme (Merge/Conquer) Aşaması

Bölme aşamasının sonunda elde edilen tek elemanlı (ve dolayısıyla sıralı) alt diziler, birleştirilmeye başlanır. Bu aşama, Merge Sort’un asıl sıralama mantığının uygulandığı yerdir.

İki sıralı alt dizi (örneğin [27, 38] ve [3, 43]) birleştirilirken, her iki dizinin başından elemanlar karşılaştırılır. Daha küçük olan eleman yeni, birleşik diziye yerleştirilir ve ilgili dizinin işaretçisi bir sonraki elemana ilerletilir. Bu işlem, her iki alt dizideki tüm elemanlar yeni diziye yerleştirilene kadar devam eder. Eğer bir dizide eleman kalmazsa, diğer dizide kalan tüm elemanlar doğrudan yeni diziye eklenir.

Örnek üzerinden birleştirme adımları:

  • [38] ve [27] birleşir -> [27, 38]
  • [43] ve [3] birleşir -> [3, 43]
  • [9] ve [82] birleşir -> [9, 82]
  • [10] tek kalır.

Daha sonra bu sıralı alt diziler tekrar birleştirilir:

  • [27, 38] ve [3, 43] birleşir -> [3, 27, 38, 43]
  • [9, 82] ve [10] birleşir -> [9, 10, 82]

Son olarak, en büyük iki sıralı alt dizi birleştirilir:

  • [3, 27, 38, 43] ve [9, 10, 82] birleşir -> [3, 9, 10, 27, 38, 43, 82]

Bu süreç, tüm dizi tek bir sıralı dizi haline gelene kadar devam eder.

Merge Sort Algoritmasının Kod Örnekleri

Java İmplementasyonu

Java’da Merge Sort implementasyonu genellikle iki ana metottan oluşur: ana özyinelemeli mergeSort metodu ve iki sıralı alt diziyi birleştiren merge metodu.


public class MergeSort {

    // Ana Merge Sort metodu
    public void mergeSort(int[] arr, int left, int right) {
        if (left < right) {
            // Diziyi ikiye böl
            int mid = (left + right) / 2;

            // Sol ve sağ yarıyı özyinelemeli olarak sırala
            mergeSort(arr, left, mid);
            mergeSort(arr, mid + 1, right);

            // Sıralanmış yarıları birleştir
            merge(arr, left, mid, right);
        }
    }

    // İki sıralı alt diziyi birleştiren yardımcı metod
    void merge(int[] arr, int left, int mid, int right) {
        // Geçici diziler için boyutları hesapla
        int n1 = mid - left + 1;
        int n2 = right - mid;

        // Geçici diziler oluştur
        int[] L = new int[n1];
        int[] R = new int[n2];

        // Verileri geçici dizilere kopyala
        for (int i = 0; i < n1; i++)
            L[i] = arr[left + i];
        for (int j = 0; j < n2; j++)
            R[j] = arr[mid + 1 + j];

        // Geçici dizileri ana diziye birleştir
        int i = 0, j = 0; // L ve R dizileri için başlangıç indeksleri
        int k = left;     // Birleştirilen ana dizi için başlangıç indeksi

        while (i < n1 && j < n2) {
            if (L[i] <= R[j]) {
                arr[k] = L[i];
                i++;
            } else {
                arr[k] = R[j];
                j++;
            }
            k++;
        }

        // L'de kalan elemanları kopyala
        while (i < n1) {
            arr[k] = L[i];
            i++;
            k++;
        }

        // R'de kalan elemanları kopyala
        while (j < n2) {
            arr[k] = R[j];
            j++;
            k++;
        }
    }

    // Test etmek için main metodu
    public static void main(String[] args) {
        int[] arr = {38, 27, 43, 3, 9, 82, 10};
        System.out.println("Sıralanmamış dizi:");
        for (int x : arr) {
            System.out.print(x + " ");
        }
        System.out.println();

        MergeSort ob = new MergeSort();
        ob.mergeSort(arr, 0, arr.length - 1);

        System.out.println("Sıralanmış dizi:");
        for (int x : arr) {
            System.out.print(x + " ");
        }
        System.out.println();
    }
}

C İmplementasyonu

C dilinde Merge Sort, bellek yönetimi ve pointer'lar nedeniyle biraz daha dikkat gerektirir, ancak temel mantık Java implementasyonu ile aynıdır.


#include 
#include  // malloc için

// İki sıralı alt diziyi birleştiren yardımcı fonksiyon
void merge(int arr[], int left, int mid, int right) {
    int i, j, k;
    int n1 = mid - left + 1;
    int n2 = right - mid;

    // Geçici diziler oluştur
    int L = (int )malloc(n1 * sizeof(int));
    int R = (int )malloc(n2 * sizeof(int));

    // Verileri geçici dizilere kopyala
    for (i = 0; i < n1; i++)
        L[i] = arr[left + i];
    for (j = 0; j < n2; j++)
        R[j] = arr[mid + 1 + j];

    // Geçici dizileri ana diziye birleştir
    i = 0; // L dizisi için başlangıç indeksi
    j = 0; // R dizisi için başlangıç indeksi
    k = left; // Birleştirilen ana dizi için başlangıç indeksi

    while (i < n1 && j < n2) {
        if (L[i] <= R[j]) {
            arr[k] = L[i];
            i++;
        } else {
            arr[k] = R[j];
            j++;
        }
        k++;
    }

    // L'de kalan elemanları kopyala
    while (i < n1) {
        arr[k] = L[i];
        i++;
        k++;
    }

    // R'de kalan elemanları kopyala
    while (j < n2) {
        arr[k] = R[j];
        j++;
        k++;
    }

    // Geçici dizileri serbest bırak
    free(L);
    free(R);
}

// Ana Merge Sort fonksiyonu
void mergeSort(int arr[], int left, int right) {
    if (left < right) {
        // Diziyi ikiye böl
        int mid = left + (right - left) / 2; // Taşmayı önlemek için bu şekilde hesaplanır

        // Sol ve sağ yarıyı özyinelemeli olarak sırala
        mergeSort(arr, left, mid);
        mergeSort(arr, mid + 1, right);

        // Sıralanmış yarıları birleştir
        merge(arr, left, mid, right);
    }
}

// Diziyi yazdırma fonksiyonu
void printArray(int arr[], int size) {
    int i;
    for (i = 0; i < size; i++)
        printf("%d ", arr[i]);
    printf("\n");
}

// Test etmek için main fonksiyonu
int main() {
    int arr[] = {38, 27, 43, 3, 9, 82, 10};
    int arr_size = sizeof(arr) / sizeof(arr[0]);

    printf("Sıralanmamış dizi:\n");
    printArray(arr, arr_size);

    mergeSort(arr, 0, arr_size - 1);

    printf("Sıralanmış dizi:\n");
    printArray(arr, arr_size);

    return 0;
}

Python İmplementasyonu

Python'da list slicing (dizi dilimleme) özelliği sayesinde Merge Sort implementasyonu daha kısa ve okunabilir olabilir. Genellikle merge işlevi, ana merge_sort fonksiyonunun içinde halledilir.


def merge_sort(arr):
    # Temel durum: Dizi 1 veya 0 elemanlı ise zaten sıralıdır
    if len(arr) <= 1:
        return arr

    # Diziyi ikiye böl
    mid = len(arr) // 2
    left_half = arr[:mid]
    right_half = arr[mid:]

    # Sol ve sağ yarıyı özyinelemeli olarak sırala
    left_half = merge_sort(left_half)
    right_half = merge_sort(right_half)

    # Sıralanmış yarıları birleştir
    return merge(left_half, right_half)

def merge(left, right):
    merged_arr = []
    i = 0  # Sol dizi için indeks
    j = 0  # Sağ dizi için indeks

    # İki diziyi karşılaştırarak birleştir
    while i < len(left) and j < len(right):
        if left[i] <= right[j]:
            merged_arr.append(left[i])
            i += 1
        else:
            merged_arr.append(right[j])
            j += 1

    # Kalan elemanları ekle (varsa)
    while i < len(left):
        merged_arr.append(left[i])
        i += 1

    while j < len(right):
        merged_arr.append(right[j])
        j += 1
    
    return merged_arr

Test etmek için örnek

if __name__ == "__main__": arr = [38, 27, 43, 3, 9, 82, 10] print("Sıralanmamış dizi:", arr) sorted_arr = merge_sort(arr) print("Sıralanmış dizi:", sorted_arr)

Merge Sort'un Performansı ve Pratik Kullanım Alanları

Zaman Karmaşıklığı (Time Complexity)

Merge Sort'un en önemli özelliklerinden biri, zaman karmaşıklığının her durumda (en iyi, ortalama ve en kötü durum) O(n log n) olmasıdır. Bu, diğer birçok sıralama algoritmasından (örneğin Quick Sort'un en kötü durumu O(n^2) olabilir) daha tutarlı ve garantili bir performansı ifade eder.

  • O(log n) bölme: Diziyi sürekli ikiye bölme işlemi log n adım sürer.
  • O(n) birleştirme: Her bölme seviyesinde, tüm elemanları birleştirmek için O(n) işlem gerekir.

Bu iki faktör birleştiğinde, toplam zaman karmaşıklığı O(n log n) olur. Bu, özellikle büyük veri setleri için oldukça verimli bir performanstır.

Uzay Karmaşıklığı (Space Complexity)

Merge Sort'un temel dezavantajlarından biri, birleştirme işlemi sırasında geçici diziler oluşturması nedeniyle ek bellek alanı gerektirmesidir. Bu ek bellek ihtiyacı O(n) kadardır. Yani, sıralanacak eleman sayısı arttıkça, kullanılan ek bellek alanı da doğrusal olarak artar. Belleğin kısıtlı olduğu sistemlerde bu bir sorun teşkil edebilir.

Avantajları ve Dezavantajları

Avantajları:

  • Kararlılık (Stability): Aynı değere sahip elemanların orijinal dizideki göreceli sıralarını korur. Bu özellik, bazı özel sıralama senaryolarında kritik öneme sahiptir.
  • Garanti Edilmiş Performans: En kötü durumda bile O(n log n) zaman karmaşıklığına sahiptir.
  • Bağlı Listeler İçin Uygunluk: Rastgele erişime ihtiyaç duymadığı için (sadece ardışık erişim), bağlı listeler üzerinde Quick Sort'tan daha verimli çalışır.
  • Harici Sıralama (External Sorting): Belleğe sığmayan büyük veri setlerini sıralamak için idealdir, çünkü veriyi diskten okuyup yazabilir.

Dezavantajları:

  • Ek Bellek İhtiyacı: O(n) ek alan gerektirir, bu da büyük veri setlerinde önemli bir dezavantaj olabilir.
  • Rekürsif Çağrı Yığını (Stack Overhead): Derin rekürsif çağrılar, özellikle çok büyük diziler için yığın taşması (stack overflow) riskine yol açabilir.
  • Küçük Diziler İçin Yavaşlık: Küçük diziler için, daha basit algoritmalar (örneğin Insertion Sort) Merge Sort'un rekürsif çağrı ve bellek kopyalama overhead'i nedeniyle daha hızlı olabilir.

Pratik Kullanım Alanları

  • Büyük Veri Setlerinin Sıralanması: Performans garantisi ve ölçeklenebilirliği sayesinde büyük veri kümeleri için tercih edilir.
  • Harici Sıralama (External Sorting): Veri belleğe sığmadığında ve disk üzerinde işlem yapılması gerektiğinde (veri tabanı yönetim sistemleri gibi).
  • Paralel Sıralama Algoritmaları: Böl ve yönet yapısı, paralel işlemcilerde kolayca paralelleştirilebilir.
  • İnversiyon Sayma (Inversion Counting): Bir dizideki tersine çevrilmiş çiftleri saymak gibi bazı özel problemlerin çözümünde Merge Sort algoritması temel alınır.

Sonuç ve Sıkça Sorulan Sorular (SSS)

Merge Sort, "böl ve yönet" stratejisini ustaca kullanan, kararlı, verimli ve güvenilir bir sıralama algoritmasıdır. O(n log n) zaman karmaşıklığı ile büyük veri setleri için ideal bir seçimdir, ancak O(n) ek bellek ihtiyacı, kaynak kısıtlı ortamlarda dikkate alınması gereken bir faktördür. Java, C ve Python gibi farklı dillerde kolayca implemente edilebilir ve modern yazılım geliştirmede hala önemli bir yere sahiptir.

Sıkça Sorulan Sorular (SSS)

Merge Sort ne zaman Quick Sort'tan daha iyidir?

Merge Sort, bellek alanı bir sorun teşkil etmediğinde, sıralama kararlılığı (aynı değerli elemanların göreceli sırasını koruma) kritik olduğunda ve en kötü durum performansından (Quick Sort'un O(n^2) olabilen en kötü durumu) kaçınmak istendiğinde Quick Sort'tan daha iyi bir seçenektir. Ayrıca, bağlı listeler gibi rastgele erişimin maliyetli olduğu veri yapılarında Merge Sort daha avantajlıdır.

Merge Sort neden kararlı bir algoritmadır?

Merge Sort, birleştirme aşamasında aynı değere sahip elemanlar karşılaştırıldığında, sol alt diziden gelen elemanı önce yerleştirerek kararlılık özelliğini korur. Bu, orijinal dizideki göreceli sıralarının bozulmamasını sağlar.

Yerinde (in-place) Merge Sort mümkün müdür?

Teorik olarak O(1) ek alan kullanan yerinde Merge Sort implementasyonları mevcuttur, ancak bu implementasyonlar genellikle oldukça karmaşıktır ve zaman karmaşıklığını artırabilir veya pratik kullanımda daha fazla karşılaştırma gerektirebilir. Bu nedenle, çoğu pratik implementasyonda O(n) ek bellek kullanımı kabul edilir.

Merge Sort'un iteratif versiyonu var mıdır?

Evet, Merge Sort'un rekürsif olmayan (iteratif) versiyonları da mevcuttur. Bu versiyonlar genellikle rekürsif çağrı yığını taşması riskini önlemek için kullanılır ve özellikle çok büyük dizilerde tercih edilebilir. Ancak, iteratif implementasyonlar rekürsif olanlara göre genellikle biraz daha karmaşık bir yapıya sahiptir.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

Gönder

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.
Mobil sürümden çık