Merge Sort
Zuletzt aktualisiert
Merge Sort ist ein Teile-und-herrsche-Algorithmus. Er teilt das Array rekursiv in Hälften, bis jedes Teilstück ein einzelnes Element enthält (das trivialerweise sortiert ist), und fügt die Teile dann geordnet wieder zusammen. Der Merge-Schritt durchläuft zwei sortierte Teilarrays mit zwei Zeigern und kopiert stets das kleinere vordere Element als Nächstes. Drücke oben auf Abspielen, um zuzusehen, wie das Array Verschmelzung für Verschmelzung neu aufgebaut wird.
Da immer in Hälften geteilt wird, läuft Merge Sort in jedem Fall in O(n log n) Zeit - der schlechteste Fall ist so gut wie der beste. Der Kompromiss ist O(n) zusätzlicher Speicher für den temporären Merge-Puffer.
Zeit- und Speicherkomplexität
| Fall | Komplexität | Anmerkungen |
|---|---|---|
| Bester Fall | O(n log n) | Halbiert die Eingabe stets |
| Durchschnittlicher Fall | O(n log n) | Zufällige Reihenfolge |
| Schlechtester Fall | O(n log n) | Garantiert - keine schlechten Eingaben |
| Speicher | O(n) | Temporärer Puffer für das Verschmelzen |
| Stabil | Ja | Gleichstände werden beim Merge links zuerst aufgelöst |
Schritt für Schritt
| Schritt | Was passiert |
|---|---|
| 1 | Hat der Bereich 0 oder 1 Elemente, ist er bereits sortiert. |
| 2 | Teile den Bereich in zwei Hälften. |
| 3 | Sortiere die linke Hälfte rekursiv mit Merge Sort. |
| 4 | Sortiere die rechte Hälfte rekursiv mit Merge Sort. |
| 5 | Verschmelze die beiden sortierten Hälften mit zwei Zeigern. |
Durchgerechnetes Beispiel
Sortieren von [5, 2, 4, 1]:
| Durchlauf | Array | Aktion |
|---|---|---|
| Teilen | [5, 2] | [4, 1] | Teile das Array in zwei Hälften |
| Teilen | [5] [2] | [4] [1] | Teile erneut, bis jedes Teilstück ein einzelnes Element ist |
| Verschmelzen | [2, 5] | [1, 4] | Verschmelze [5],[2] zu [2, 5] und [4],[1] zu [1, 4] |
| Verschmelzen | [1, 2, 4, 5] | Verschmelze [2, 5] und [1, 4]: wähle 1, dann 2, dann 4, dann 5 |
| Fertig | [1, 2, 4, 5] | Das Array ist vollständig sortiert |
Wann Merge Sort verwenden
| Verwenden, wenn | Vermeiden, wenn |
|---|---|
Du einen garantierten O(n log n)-Worst-Case brauchst | Der Speicher knapp ist und O(n) Zusatzspeicher inakzeptabel ist |
| Stabilität wichtig ist (gleiche Schlüssel behalten ihre Reihenfolge) | Du kleine Arrays sortierst, bei denen Insertion Sort schneller ist |
| Du eine verkettete Liste sortierst | In-Place-Sortierung eine harte Anforderung ist |
| Die Daten zu groß für den RAM sind (externes Sortieren) | Cache-Lokalität dominiert und Quicksorts In-Place-Durchläufe gewinnen |
Merge Sort-Code
Eine saubere, lauffähige Merge Sort-Implementierung in Python, JavaScript, Java, C++, C. Wähle eine Sprache, kopiere den Code oder öffne ihn vorgeladen im Coddy-Playground.
Merge Sort-Code in Python
1def merge_sort(a):2 if len(a) <= 1:3 return a4 mid = len(a) // 25 left = merge_sort(a[:mid])6 right = merge_sort(a[mid:])7 return merge(left, right)8
9
10def merge(left, right):11 out = []12 i = j = 013 while i < len(left) and j < len(right):14 if left[i] <= right[j]:15 out.append(left[i])16 i += 117 else:18 out.append(right[j])19 j += 120 out.extend(left[i:])21 out.extend(right[j:])22 return out23
24
25nums = [38, 27, 43, 3, 9, 82, 10]26print("Before:", nums)27print("After: ", merge_sort(nums))Merge Sort-Code in JavaScript
1function mergeSort(arr) {2 if (arr.length <= 1) return arr;3 const mid = Math.floor(arr.length / 2);4 const left = mergeSort(arr.slice(0, mid));5 const right = mergeSort(arr.slice(mid));6 return merge(left, right);7}8
9// Merge two sorted arrays into one sorted array10function merge(left, right) {11 const out = [];12 let i = 0;13 let j = 0;14 while (i < left.length && j < right.length) {15 out.push(left[i] <= right[j] ? left[i++] : right[j++]);16 }17 return out.concat(left.slice(i), right.slice(j));18}19
20const data = [5, 2, 9, 1, 7, 3];21console.log("Before:", data);22console.log("Sorted:", mergeSort(data));Merge Sort-Code in Java
1import java.util.Arrays;2
3public class Main {4 static void mergeSort(int[] arr, int left, int right) {5 if (left >= right) return;6 int mid = (left + right) / 2;7 mergeSort(arr, left, mid);8 mergeSort(arr, mid + 1, right);9 merge(arr, left, mid, right);10 }11
12 // Merge two sorted halves into a temp array, then copy back13 static void merge(int[] arr, int left, int mid, int right) {14 int[] tmp = new int[right - left + 1];15 int i = left, j = mid + 1, k = 0;16 while (i <= mid && j <= right) {17 tmp[k++] = arr[i] <= arr[j] ? arr[i++] : arr[j++];18 }19 while (i <= mid) tmp[k++] = arr[i++];20 while (j <= right) tmp[k++] = arr[j++];21 System.arraycopy(tmp, 0, arr, left, tmp.length);22 }23
24 public static void main(String[] args) {25 int[] arr = {38, 27, 43, 3, 9, 82, 10};26 System.out.println("Before: " + Arrays.toString(arr));27 mergeSort(arr, 0, arr.length - 1);28 System.out.println("After: " + Arrays.toString(arr));29 }30}Merge Sort-Code in C++
1#include <iostream>2#include <vector>3
4void printVec(const std::vector<int>& a) {5 for (int x : a) std::cout << x << " ";6 std::cout << "\n";7}8
9void merge(std::vector<int>& a, int lo, int mid, int hi) {10 std::vector<int> tmp;11 tmp.reserve(hi - lo + 1);12 int i = lo, j = mid + 1;13 while (i <= mid && j <= hi) {14 if (a[i] <= a[j]) tmp.push_back(a[i++]);15 else tmp.push_back(a[j++]);16 }17 while (i <= mid) tmp.push_back(a[i++]);18 while (j <= hi) tmp.push_back(a[j++]);19 for (size_t k = 0; k < tmp.size(); ++k) a[lo + k] = tmp[k];20}21
22void mergeSort(std::vector<int>& a, int lo, int hi) {23 if (lo >= hi) return;24 int mid = lo + (hi - lo) / 2;25 mergeSort(a, lo, mid); // sort the left half26 mergeSort(a, mid + 1, hi); // sort the right half27 merge(a, lo, mid, hi); // merge the sorted halves28}29
30int main() {31 std::vector<int> data = {38, 27, 43, 3, 9, 82, 10};32 std::cout << "Before: ";33 printVec(data);34 mergeSort(data, 0, static_cast<int>(data.size()) - 1);35 std::cout << "After: ";36 printVec(data);37 return 0;38}Merge Sort-Code in C
1#include <stdio.h>2#include <stdlib.h>3
4void printArr(const int a[], int n) {5 for (int i = 0; i < n; i++) printf("%d ", a[i]);6 printf("\n");7}8
9void merge(int a[], int lo, int mid, int hi) {10 int* tmp = malloc((hi - lo + 1) * sizeof(int));11 int i = lo, j = mid + 1, k = 0;12 while (i <= mid && j <= hi) {13 if (a[i] <= a[j]) tmp[k++] = a[i++];14 else tmp[k++] = a[j++];15 }16 while (i <= mid) tmp[k++] = a[i++];17 while (j <= hi) tmp[k++] = a[j++];18 for (k = 0; k <= hi - lo; k++) a[lo + k] = tmp[k];19 free(tmp);20}21
22void mergeSort(int a[], int lo, int hi) {23 if (lo >= hi) return;24 int mid = lo + (hi - lo) / 2;25 mergeSort(a, lo, mid); // sort the left half26 mergeSort(a, mid + 1, hi); // sort the right half27 merge(a, lo, mid, hi); // merge the sorted halves28}29
30int main(void) {31 int data[] = {38, 27, 43, 3, 9, 82, 10};32 int n = sizeof(data) / sizeof(data[0]);33 printf("Before: ");34 printArr(data, n);35 mergeSort(data, 0, n - 1);36 printf("After: ");37 printArr(data, n);38 return 0;39}Merge Sort FAQ
Wie ist die Zeitkomplexität von Merge Sort?
O(n log n), weil es das Array stets in Hälften teilt. Es benötigt O(n) zusätzlichen Speicher für den Merge-Puffer.Ist Merge Sort stabil?
Warum Merge Sort statt Quicksort verwenden?
O(n log n) selbst bei bösartigen Eingaben und ist stabil, während Quicksort auf O(n²) degenerieren kann. Merge Sort wird außerdem für verkettete Listen und externes Sortieren bevorzugt. Der Nachteil ist der O(n) zusätzliche Speicher.Was ist der Unterschied zwischen Merge Sort und Quicksort?
O(log n) Stack-Speicher, während Merge Sort blind in Hälften teilt und mit einem O(n)-Puffer verschmilzt. Quicksort ist in der Praxis wegen der Cache-Lokalität meist schneller, aber Merge Sort hat einen garantierten O(n log n)-Worst-Case und ist stabil.Wann sollte ich Merge Sort in der Praxis verwenden?
O(n log n)-Schranke brauchst, beim Sortieren verketteter Listen (wo kein wahlfreier Zugriff nötig ist) oder beim externen Sortieren von Daten, die zu groß für den Speicher sind. Vermeide es bei knappem Speicher, da es O(n) zusätzlichen Platz benötigt.Sortiert Merge Sort in-place?
O(n) großen temporären Puffer zum Verschmelzen der beiden Hälften und ist daher nicht in-place. In-Place-Merge-Varianten existieren, sind aber komplex und entweder langsamer oder verlieren die Stabilität, weshalb die pufferbasierte Version die gängige Wahl ist.