Insertion Sort in Java

Einfügesortierung in Java

1. Überblick

In diesem Tutorial werden wirthe Insertion Sort algorithm and have a look at its Java implementation diskutieren.

Insertion Sort ist ein effizienter Algorithmus zum Bestellen einer kleinen Anzahl von Artikeln. Diese Methode basiert auf der Art und Weise, wie Kartenspieler eine Hand aus Spielkarten sortieren.

Wir beginnen mit einer leeren linken Hand und den auf den Tisch gelegten Karten. Wir nehmen dann jeweils eine Karte vom Tisch und setzen sie in der linken Hand an der richtigen Position ein. Um die richtige Position für eine neue Karte zu finden, vergleichen wir sie von rechts nach links mit dem bereits sortierten Kartensatz in der Hand.

Beginnen wir mit dem Verständnis der Algorithmusschritte in Pseudocode-Form.

2. Pseudocode

Wir werden unseren Pseudocode für die Einfügesortierung als Prozedur mit dem NamenINSERTION-SORT präsentieren und als Parameter ein ArrayA[1 .. n] von n zu sortierenden Elementen verwenden. The algorithm sorts the input array in-place  (durch Neuanordnen der Elemente innerhalb des Arrays A).

Nach Abschluss der Prozedur enthält das Eingabearray A eine Permutation der Eingabesequenz, jedoch in sortierter Reihenfolge:

INSERTION-SORT(A)

for i=2 to A.length
    key = A[i]
    j = i - 1
    while j > 0 and A[j] > key
        A[j+1] = A[j]
        j = j - 1
    A[j + 1] = key

Lassen Sie uns den obigen Algorithmus kurz durchgehen.

Der Indexi gibt die Position des aktuellen Elements im zu verarbeitenden Array an.

Wir beginnen mit dem zweiten Element, da per Definition ein Array mit einem Element als sortiert betrachtet wird. Das Element am Indexi wird alskey bezeichnet. Sobald diekey, vorliegen, befasst sich der zweite Teil des Algorithmus mit dem Finden seines korrekten Index. If the key is smaller than the value of the item at index j, then the key moves one position to the left. Der Prozess wird fortgesetzt, bis wir ein Element erreichen, das kleiner als der Schlüssel ist.

Es ist wichtig zu beachten, dass vor dem Start der Iteration zum Ermitteln der korrekten Position vonkey bei Indexi das ArrayA[1 .. j – 1] bereitssorted ist.

3. Imperative Implementierung

Für den imperativen Fall werden wir eine Funktion namensinsertionSortImperative schreiben, die als Parameter ein Array von ganzen Zahlen verwendet. Die Funktion beginnt mit dem Durchlaufen des Arrays ab dem zweiten Element.

Zu jedem Zeitpunkt während der Iteration istwe could think of this array as being logically divided into two portions;die linke Seite die sortierte und die rechte Seite die noch nicht sortierten Elemente.

Ein wichtiger Hinweis hierbei ist, dass nach dem Finden der richtigen Position, an der das neue Element eingefügt wird,we shift (and not swap) the items to the right, um einen Speicherplatz dafür freizugeben.

public static void insertionSortImperative(int[] input) {
    for (int i = 1; i < input.length; i++) {
        int key = input[i];
        int j = i - 1;
        while (j >= 0 && input[j] > key) {
            input[j + 1] = input[j];
            j = j - 1;
        }
        input[j + 1] = key;
    }
}

Als nächstes erstellen wir einen Test für die obige Methode:

@Test
public void givenUnsortedArray_whenInsertionSortImperative_thenSortedAsc() {
    int[] input = {6, 2, 3, 4, 5, 1};
    InsertionSort.insertionSortImperative(input);
    int[] expected = {1, 2, 3, 4, 5, 6};
    assertArrayEquals("the two arrays are not equal", expected, input);
}

Der obige Test beweist, dass der Algorithmus das Eingabearray<6, 2, 3, 4, 5, 1> in aufsteigender Reihenfolge korrekt sortiert.

4. Rekursive Implementierung

Die Funktion für den rekursiven Fall heißtinsertionSortRecursive . Sand akzeptiert als Eingabe ein Array von ganzen Zahlen (wie für den imperativen Fall).

Der Unterschied zum imperativen Fall (trotz der Tatsache, dass er rekursiv ist) besteht darin, dass ercalls an overloaded function with a second argument that equals the number of items to sort. beträgt

Wenn wir das gesamte Array sortieren möchten, übergeben wir eine Anzahl von Elementen, die seiner Länge entsprechen:

public static void insertionSortRecursive(int[] input) {
    insertionSortRecursive(input, input.length);
}

Der rekursive Fall ist etwas schwieriger. The base case occurs when we attempt to sort an array with one item. In diesem Fall tun wir nichts.

Alle nachfolgenden rekursiven Aufrufe sortieren einen vordefinierten Teil des Eingabearrays - beginnend mit dem zweiten Element bis zum Ende des Arrays:

private static void insertionSortRecursive(int[] input, int i) {
    if (i <= 1) {
        return;
    }
    insertionSortRecursive(input, i - 1);
    int key = input[i - 1];
    int j = i - 2;
    while (j >= 0 && input[j] > key) {
        input[j + 1] = input[j];
        j = j - 1;
    }
    input[j + 1] = key;
}

Und so sieht der Aufrufstapel für ein Eingabearray mit 6 Elementen aus:

insertionSortRecursive(input, 6)
insertionSortRecursive(input, 5) and insert the 6th item into the sorted array
insertionSortRecursive(input, 4) and insert the 5th item into the sorted array
insertionSortRecursive(input, 3) and insert the 4th item into the sorted array
insertionSortRecursive(input, 2) and insert the 3rd item into the sorted array
insertionSortRecursive(input, 1) and insert the 2nd item into the sorted array

Sehen wir uns auch den Test dafür an:

@Test
public void givenUnsortedArray_whenInsertionSortRecursively_thenSortedAsc() {
    int[] input = {6, 4, 5, 2, 3, 1};
    InsertionSort.insertionSortRecursive(input);
    int[] expected = {1, 2, 3, 4, 5, 6};
    assertArrayEquals("the two arrays are not equal", expected, input);
}

Der obige Test beweist, dass der Algorithmus das Eingabearray<6, 2, 3, 4, 5, 1> in aufsteigender Reihenfolge korrekt sortiert.

5. Zeit- und Raumkomplexität

The time taken by the INSERTION-SORT procedure to run is O(n^2). Für jedes neue Element durchlaufen wir den bereits sortierten Teil des Arrays von rechts nach links, um die richtige Position zu finden. Dann fügen wir es ein, indem wir die Elemente um eine Position nach rechts verschieben.

Der Algorithmus sortiert an Ort und Stelle so seinespace complexity is O(1) for the imperative implementation and O(n) for the recursive implementation.

6. Fazit

In diesem Tutorial haben wir gesehen, wie die Einfügesortierung implementiert wird.

Dieser Algorithmus ist nützlich, um eine kleine Anzahl von Elementen zu sortieren. It becomes inefficient when sorting input sequences having more than 100 items. 

Beachten Sie, dass es trotz seiner quadratischen Komplexität ohne zusätzlichen Platz sortiert wird, wie dies beimerge sort der Fall ist.

Der gesamte Code konnteover on GitHub gefunden werden.