Shellsort-Algorithmus mit Beispiel

⚡ Intelligente Zusammenfassung

Shell Sort ist ein In-Place-Vergleichsalgorithmus, der Insertion Sort verallgemeinert, indem er weit voneinander entfernte Elemente vergleicht und dann den Abstand verringert, bis benachbarte Elemente sortiert sind.

  • 📊 Definition: Eine In-Place-Verallgemeinerung des Insertion Sort, die von Donald Shell im Jahr 1959 vorgeschlagen wurde und eine absteigende Lückenfolge verwendet.
  • 🔀 Lückensequenzen: Shells ursprüngliche Sequenz lautet n/2, n/4, …, 1; Knuth-, Sedgewick- und Ciura-Sequenzen schneiden in der Praxis besser ab.
  • ⚡ Komplexität: Im besten Fall O(n log n), im schlechtesten Fall O(n^2) und mit einem zusätzlichen Speicherplatz von O(1).
  • ✅ Anwendungsfälle: Der Linux-Kernel, uClibc und bzip2 verwenden Shell Sort, um Rekursion und zusätzlichen Stack-Speicher zu vermeiden.
  • 🤖 KI-Perspektive: KI-Assistenten können Lückensequenzen vorschlagen und auf Anfrage animierte Shell-Sort-Visualisierungen generieren.

Was ist Shellsort?

Shellsort, auch Shell-Verfahren genannt, ist ein effizienter, auf Vergleichen basierender Sortieralgorithmus, der direkt im Speicher durchgeführt wird. Benannt nach Donald Shell, der die Idee 1959 vorstellte, stellt er eine verallgemeinerte Erweiterung des Insertionsort-Algorithmus dar, die dessen quadratisches Verhalten bei verstreuten Daten überwindet.

Die Grundidee besteht darin, weit voneinander entfernte Elemente zu gruppieren, jede Gruppe mithilfe des Einfügesortierverfahrens zu sortieren und den Abstand schrittweise zu verringern, bis er eins beträgt. Dann ist das Array nahezu sortiert.

Diese Lücke, das Intervall, folgt einer gewählten Sequenz, wie beispielsweise Shells Original, Knuths, Hibbards oder Sedgewicks. Shells Original ist n/2, n/4, ..., 1.

Shell-Sortieralgorithmus

Schritt 1) Initialisiere den Intervallwert h = n/2, wobei n die Größe des Arrays ist.

Schritt 2) Platziere alle Elemente innerhalb eines Abstands des Intervalls h in einer Unterliste.

Schritt 3) Sortieren Sie jede Teilliste mithilfe des Einfügesortierverfahrens.

Schritt 4) Setze ein neues Intervall h = h/2.

Schritt 5) Falls h > 0, kehre zu Schritt 2 zurück. Andernfalls gehe zu Schritt 6.

Schritt 6) Das resultierende Array ist nun vollständig sortiert.

So funktioniert die Shell-Sortierung

Beim Einfügesortierverfahren werden Elemente jeweils nur um eine Position verschoben. Shellsort hingegen teilt das Array anhand des Intervalls in weit auseinanderliegende Teillisten auf und wendet das Einfügesortierverfahren auf jede Teilliste an.

Mit abnehmendem Intervall wächst die Größe der Teilliste. Da frühere Durchläufe die Daten nur teilweise sortiert hinterlassen, benötigen kleinere Intervalle deutlich weniger Vertauschungen als die Ausführung von Sortieren durch Einfügen von Grund auf. Die folgende Abbildung veranschaulicht einen Shellsort-Durchlauf.

Shell Sort funktioniert

Funktionsweise des Shellsort-Algorithmus mit Beispiel

Sortieren wir das untenstehende Array mit Shell Sort.

Funktionsweise des Shell-Sort-Algorithmus

Schritt 1) Die Arraygröße beträgt 8, daher ist der Anfangsintervallwert h = 8/2 = 4.

Schritt 2) Gruppiere Elemente im Abstand von vier Positionen. Teillisten: {8, 1}, {6, 4}, {7, 5}, {2, 3}.

Funktionsweise des Shell-Sort-Algorithmus

Schritt 3) Sortiere jede Teilliste mit dem Einfügesortierverfahren. Eine temporäre Variable speichert den jeweils eingefügten Wert während der Verschiebung der Elemente. Nach dem Vertauschen sieht das Array folgendermaßen aus.

Funktionsweise des Shell-Sort-Algorithmus

Schritt 4) Verringere das Intervall. Das neue Intervall ist h = 4/2 = 2.

Schritt 5) Da 2 > 0, kehre zu Schritt 2 zurück und gruppiere Elemente, die zwei Positionen voneinander entfernt sind: {1, 5, 8, 7} und {4, 2, 6, 3}.

Funktionsweise des Shell-Sort-Algorithmus

Sortiere die erste Teilliste. Das Array sieht dann so aus:

Funktionsweise des Shell-Sort-Algorithmus

Nach dem Sortieren der zweiten Teilliste:

Funktionsweise des Shell-Sort-Algorithmus

Verringern Sie das Intervall erneut auf h = 2/2 = 1. Mit einem Abstand von eins führt Shell Sort einen letzten Insertionsort-Durchlauf über das gesamte Array durch, wie unten gezeigt.

Funktionsweise des Shell-Sort-Algorithmus

Funktionsweise des Shell-Sort-Algorithmus

Funktionsweise des Shell-Sort-Algorithmus

Schritt 6) Teilt man das Intervall erneut, erhält man 0. Das Array ist nun vollständig sortiert:

Funktionsweise des Shell-Sort-Algorithmus

Pseudo-Code für Shell Sort

Start
Input array a of size n
for (interval = n / 2; interval > 0; interval /= 2)
    for (i = interval; i < n; i += 1)
        temp = a[i];
        for (j = i; j >= interval && a[j - interval] > temp; j -= interval)
            a[j] = a[j - interval];
        a[j] = temp;
End

Shell-Sortierprogramm in C/C++

Eingang:

//Shell Sort Program in C/C++
#include <bits/stdc++.h>
using namespace std;
void ShellSort(int data[], int size) {
    for (int interval = size / 2; interval > 0; interval /= 2) {
        for (int i = interval; i < size; i += 1) {
            int temp = data[i];
            int j;
            for (j = i; j >= interval && data[j - interval] > temp; j -= interval) {
                data[j] = data[j - interval];
            }
            data[j] = temp;
        }
    }
}
int main() {
    int data[] = {8, 6, 7, 2, 1, 4, 5, 3};
    int size = sizeof(data) / sizeof(data[0]);
    ShellSort(data, size);
    cout << "Sorted Output: \n";
    for (int i = 0; i < size; i++)
        cout << data[i] << " ";
    cout << "\n";
}

Ausgang:

Sorted Output:

1 2 3 4 5 6 7 8

Shell Sort Beispiel in Python

Eingang:

#Shell Sort Example in Python
def ShellSort(data, size):
    interval = size // 2
    while interval > 0:
        for i in range(interval, size):
            temp = data[i]
            j = i
            while j >= interval and data[j - interval] > temp:
                data[j] = data[j - interval]
                j -= interval
            data[j] = temp
        interval //= 2
data = [8, 6, 7, 2, 1, 4, 5, 3]
ShellSort(data, len(data))
print('Sorted Output:')
print(data)

Ausgang:

Sorted Output:
[1, 2, 3, 4, 5, 6, 7, 8]

Anwendungen von Shell Sort

Der Shellsort findet sich auch heute noch in modernen Systemen, in denen es auf Speicherplatz oder Einfachheit ankommt.

  • Das Linux-Kernel verwendet Shell Sort an Stellen, an denen die Vermeidung eines Aufrufstapels wichtig ist.
  • Die eingebettete C-Bibliothek uClibc verwendet Shell Sort, um den Speicherverbrauch gering zu halten.
  • bzip2 verwendet Shell Sort, um tiefe Rekursionen beim Blocksortieren zu vermeiden.
  • Eingebettete Firmware bevorzugt Shell Sort für kleine Datensätze, bei denen Rekursion eingeschränkt ist.

Vor- und Nachteile der Schalensortierung

Vorteile Nachteile
Es wird kein Aufrufstapel benötigt, was ideal für eingebettete Systeme ist. Für sehr große Arrays ist dies nicht die schnellste Option.
Einfach zu implementieren mit geringem Codeaufwand. Die Leistung verschlechtert sich bei Daten mit weit verteilten Elementen.
Effizient für mittelgroße oder teilweise sortierte Arrays. Die Worst-Case-Zeitkomplexität reagiert empfindlich auf die gewählte Lückensequenz.
Funktioniert direkt am Speicherort und nutzt daher permanenten Hilfsspeicher. Es handelt sich nicht um eine stabile Sortierung, daher kann sich die relative Reihenfolge gleicher Schlüssel ändern.

Shell-Sort-Komplexitätsanalyse

Zeitliche Komplexität der Shell-Sortierung

Die Zeitkomplexität des Shellsort-Algorithmus hängt von der verwendeten Lückensequenz ab.

Im besten Fall, wenn das Array bereits nahezu vollständig angeordnet ist, benötigt jeder Durchlauf nur eine logarithmische Anzahl von Tests, was O(n log n) ergibt.

Im schlimmsten Fall ist das Array so angeordnet, dass die Elemente die maximale Anzahl an Vergleichen benötigen, und die letzte Inkrementierung dominiert bei O(n^2) mit Shells ursprünglicher Sequenz.

  1. Beste-Case-Komplexität: O(n log n)
  2. Die durchschnittliche Komplexität liegt zwischen O(n log n) und O(n^(4/3)), abhängig von der Lückensequenz.
  3. Worst-Case-Komplexität: O(n^2) mit Shells ursprünglicher Sequenz

Die beste universelle Gap-Sequenz ist noch immer eine offene Forschungsfrage, obwohl sich die Sequenzen von Sedgewick und Ciura in der Praxis gut bewähren.

Komplexität des Shell-Sortierraums

Shell Sort benötigt keine Hilfsarrays, daher ist die Speicherkomplexität unabhängig von der Eingabegröße O(1), was einer seiner größten praktischen Vorteile ist.

Häufig gestellte Fragen

Shell Sort ist ein In-Place-Vergleichssortieralgorithmus, der von Donald Shell im Jahr 1959 vorgeschlagen wurde. Er verallgemeinert Insertion Sort, indem er weit voneinander entfernte Elemente vergleicht und dann den Abstand verringert, bis benachbarte Elemente sortiert sind, was die Anzahl der Vertauschungen drastisch reduziert.

Die beste Zeitkomplexität beträgt O(n log n), die schlechteste O(n²) mit Shells ursprünglicher Sequenz. Bessere Gap-Sequenzen wie die von Sedgewick reduzieren die schlechteste Komplexität auf etwa O(n⁴/³). Die Speicherkomplexität beträgt O(1).

Nein, Shellsort ist nicht stabil. Da Elemente über große Lücken hinweg verglichen und vertauscht werden, kann sich die relative Reihenfolge zweier gleicher Schlüssel während eines Durchlaufs ändern. Wenn Stabilität wichtig ist, verwenden Sie stattdessen Mergesort oder eine stabile Variante von Insertionsort.

Beim Insertion Sort werden Elemente jeweils um eine Position verschoben. Shell Sort vergleicht zunächst weit voneinander entfernte Elemente und verringert dann schrittweise den Abstand. Das Ergebnis ist ein nahezu sortiertes Array, sobald der Abstand eins erreicht hat, sodass der letzte Durchlauf des Insertion Sort sehr schnell abgeschlossen ist.

KI-Assistenten analysieren die Größe, Verteilung und Einschränkungen Ihres Datensatzes und empfehlen anschließend einen Algorithmus wie Shellsort, Quicksort oder Radixsort. Sie können außerdem Benchmark-Skripte generieren, die Laufzeit und Speichernutzung vergleichen, sodass Sie die Empfehlung anhand realer Arbeitslasten überprüfen können.

Ja. KI-Tools können animierte Visualisierungen des Shellsort-Algorithmus generieren, die Lückengruppen, Vergleiche und Vertauschungen in Echtzeit hervorheben. Solche Visualisierungen helfen Lernenden zu erkennen, wie sich das Intervall verkleinert und wie das Array mit jedem Durchlauf einem sortierten Zustand annähert.

Fassen Sie diesen Beitrag mit folgenden Worten zusammen: