Binärer Suchalgorithmus in Java

1. Überblick

In diesem Artikel werden die Vorteile einer binären Suche gegenüber einer einfachen linearen Suche behandelt und die Implementierung in Java beschrieben.

Nehmen wir an, wir sind im Weinhandel tätig und Millionen von Käufern besuchen täglich unsere Anwendung.

Über unsere App kann ein Kunde Artikel mit einem Preis unter n Dollar herausfiltern, eine Flasche aus den Suchergebnissen auswählen und in den Warenkorb legen. Wir haben Millionen von Benutzern, die Weine mit einem Preislimit pro Sekunde suchen. Die Ergebnisse müssen schnell sein.

Im Backend führt unser Algorithmus eine lineare Suche durch die gesamte Weinliste durch, wobei die vom Kunden eingegebene Preisgrenze mit dem Preis jeder Weinflasche in der Liste verglichen wird.

Dann werden Artikel zurückgegeben, deren Preis unter oder gleich der Preisgrenze liegt. Diese lineare Suche hat eine zeitliche Komplexität von O (n) .

Dies bedeutet, je mehr Weinflaschen in unserem System vorhanden sind, desto länger dauert es. Die Suchzeit erhöht sich proportional zur Anzahl der neu eingeführten Elemente.

Wenn wir anfangen, Artikel in sortierter Reihenfolge zu speichern und nach Artikeln mit der binären Suche zu suchen, können wir eine Komplexität von O (log n) erreichen.

  • Bei der binären Suche nimmt die von den Suchergebnissen benötigte Zeit naturgemäß mit der Größe des Datensatzes zu, jedoch nicht proportional. **

3. Binäre Suche

Einfach ausgedrückt: Der Algorithmus vergleicht den key -Wert mit dem mittleren Element des Arrays. Wenn sie ungleich sind, wird die Hälfte, in der der Schlüssel nicht Teil sein kann, eliminiert und die Suche wird für die verbleibende Hälfte fortgesetzt, bis sie erfolgreich ist.

Denken Sie daran - der Schlüsselaspekt hierbei ist, dass das Array bereits sortiert ist.

Wenn die Suche mit der verbleibenden Hälfte leer ist, befindet sich der key nicht im Array.

3.1. Iteratives Impl

public int runBinarySearchIteratively(
  int[]sortedArray, int key, int low, int high) {
    int index = Integer.MAX__VALUE;

    while (low <= high) {
        int mid = (low + high)/2;
        if (sortedArray[mid]< key) {
            low = mid + 1;
        } else if (sortedArray[mid]> key) {
            high = mid - 1;
        } else if (sortedArray[mid]== key) {
            index = mid;
            break;
        }
    }
    return index;
}

Die runBinarySearchIterively -Methode benötigt einen sortedArray , key

Das middle ist der mittlere Index des sortedArray . Jetzt führt der Algorithmus eine while -Schleife aus, die den key mit dem Arraywert des mittleren Index des sortedArray vergleicht.

3.2. Rekursives Impl

Schauen wir uns nun auch eine einfache, rekursive Implementierung an:

public int runBinarySearchRecursively(
  int[]sortedArray, int key, int low, int high) {
    int middle = (low + high)/2;

    if (high < low) {
        return -1;
    }

    if (key == sortedArray[middle]) {
        return middle;
    } else if (key < sortedArray[middle]) {
        return runBinarySearchRecursively(
          sortedArray, key, low, middle - 1);
    } else {
        return runBinarySearchRecursively(
          sortedArray, key, middle + 1, high);
    }
}

Die runBinarySearchRecursively -Methode akzeptiert einen sortedArray -, key-, low - und high -Index des sortedArray__.

3.3. Arrays.binarySearch () verwenden

int index = Arrays.binarySearch(sortedArray, key);

A sortiertArray und ein int key , das im Array von Ganzzahlen gesucht werden soll, werden als Argumente an die binarySearch -Methode der Java-Klasse Arrays übergeben.

3.4. Collections.binarySearch () verwenden

int index = Collections.binarySearch(sortedList, key);

A sortierteListe

3.5. Performance

  • Die Verwendung eines rekursiven oder iterativen Ansatzes für das Schreiben des Algorithmus hängt hauptsächlich von persönlichen Vorlieben ab.

{leer} 1. Rekursion kann langsamer sein, da ein stack -Overhead aufrechterhalten wird, und normalerweise mehr Speicherplatz 2 beansprucht wird. Rekursion ist nicht _stack - -freundlich. Dies kann zu StackOverflowException_ bei der Verarbeitung großer Datenmengen führen. 3. Rekursion fügt dem Code Klarheit hinzu, da er im Vergleich zum iterativen Ansatz kürzer wird

Im Idealfall führt eine binäre Suche im Gegensatz zu einer linearen Suche nach großen Werten von n weniger Vergleiche durch. Bei kleineren Werten von n könnte die lineare Suche besser abschneiden als eine binäre Suche.

Man sollte wissen, dass diese Analyse theoretisch ist und je nach Kontext variieren kann.

Außerdem benötigt der binäre Suchalgorithmus einen sortierten Datensatz, der auch seine Kosten hat. Wenn wir zum Sortieren der Daten einen Merge-Sortier-Algorithmus verwenden, wird unserem Code eine zusätzliche Komplexität von n log n hinzugefügt.

Zuerst müssen wir unsere Anforderungen genau analysieren und dann entscheiden, welcher Suchalgorithmus unseren Anforderungen am besten entspricht.

4. Fazit

Dieses Tutorial zeigt eine binäre Suchalgorithmus Implementierung und ein Szenario, wo es vorzuziehen wäre es statt einer linearen Suche zu verwenden.

Den Code für das Tutorial https://github.com/eugenp/tutorials/tree/master/algorithms-m Miscellaneous-1 …​ finden Sie auf GitHub].