Home > Informatik > Einführung in die OOP > 6. Suchenverfahren > 6.3 Die binäre Suche

6.3 Die binäre Suche

Inhalt dieser Seite

6.3.1 Allgemeines zur binären Suche

Wenn die zu durchsuchenden Daten sortiert sind, kann man ein sehr viel effizienteres Suchverfahren anwenden als die lineare bzw. sequentielle Suche, nämlich die binäre Suche.

Die binäre Suche erfolgt nach dem Prinzip "Teile und herrsche". Das heißt, man teilt die zu durchsuchenden Daten in ein mittleres Element und zwei Hälften links und rechts davon.

Sollte das mittlere Element mit dem Suchbegriff oder der Suchzahl übereinstimmen, ist die Suche erfolgreich beendet. Andernfalls wird entweder in der linken oder in der rechten Hälfte nach dem gleichen Verfahren weitergesucht.

Flussdiagramm der binären Suche
Autor: Ulrich Helmich 2/2026, Lizenz: Public domain

Hier sehen wir ein Flussdiagramm, das den Algorithmus der binären Suche darstellt.

Achten Sie darauf, dass ein Flussdiagramm nicht die Syntax einer Programmiersprache einhalten muss, sondern relativ frei gestaltet werden kann.

6.3.2 Veranschaulichung der binären Suche

Wir wollen nun die binäre Suche in einem Array aus int-Zahlen genauer untersuchen:

1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39

Die Suchzahl ist 31.

Mit mitte=(links+rechts)/2 berechnen wir den Index des mittleren Elementes:

mitte = (0 + 19) / 2 = 9

Achten Sie darauf, dass es sich hier um eine ganzzahlige Division handelt, von dem Ergebnis 9,5 wird also nur der ganzzahlige Anteil 9 übernommen.

1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39

Die 19 ist unser mittleres Element. Da diese Zahl nicht mit dem Suchwert übereinstimmt, müssen wir die Suche fortsetzen. Es wird nun die folgende Überprüfung durchgeführt:

array[mitte] > suchwert ?

Da der Suchwert 31 größer ist als der Wert in der Mitte (19), wird in der rechten Hälfte des Arrays weitergesucht. Der linke Grenzwert muss dann neu berechnet werden:

links = mitte+1

Damit wird das Element an Position 10 (die 21) zum neuen linken Grenzwert. Die Zahlen links der 19 und die 19 selbst können wir ab jetzt ignorieren. Mit

mitte = (10 + 19) / 2 = 14

erhalten wir das mittlere Element des rechten Teilbereichs:

1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39

Die Suchzahl 31 ist größer als die 29, also wird im rechten Teil-Array weitergesucht. Der linke Grenzwert wird jetzt auf 14 + 1 = 15 gesetzt, der rechte Grenzwert bleibt weiterhin 19.

Die neue Mitte des neuen Teilbereichs berechnet sich aus

mitte = (15 + 19) / 2 = 17

1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39

Da die Suchzahl kleiner ist als die 35, wird im linken Teil-Array weitergesucht. Der Grenzwert links = 15 bleibt bestehen, der Grenzwert rechts wird auf 16 gesetzt .

Die neue Mitte berechnet sich nach

mitte = (15 + 16) / 2 = 15

jetzt an Position 15 und hat den Wert 31:

1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39

Die Bedingung array[mitte] == suchwert ist nun erfüllt, daher kann die Suche erfolgreich mit dem Rückgabewert 15 beendet werden.

Wenn Sie mitgezählt haben, werden Sie auf fünf Vergleiche gekommen sein, die wir durchführen mussten, um die Suchzahl zu finden. Bei einer linearen Suche hätten wir deutlich mehr Vergleiche benötigt.

Allerdings hätte man die kleinen Zahlen 1, 3, 5 etc. bei einer linearen Suche genau so schnell oder sogar noch schneller gefunden als bei der binären Suche.

6.3.3 Quantitativer Vergleich binär - linear

Mathematiker würden nun eine schöne und komplexe Formel aufstellen, mit der man sofort ausrechnen kann, wie groß die durchschnittliche Suchzeit bei der binären Suche ist.

Informatiker sind da eher praktischer eingestellt. Wir schreiben uns einfach ein kleines Java-Programm, in dem wir ein sortiertes Array einmal sequentiell und einmal binär durchsuchen - und zwar nicht mit einer Suchzahl, sondern mit einer ganzen Reihe von Suchzahlen.

Die Anzahl der Vergleiche in den beiden Methoden wird mitgezählt, um am Ende kommt man zu einem quantitativen Ergebnis für die durchschnittliche Zahl der Vergleiche bei beiden Methoden.

Das Methode zur binären Suche sieht so aus:

  public int vergleicheBinaer(int[] a, int suchzahl)
    {
        int links = 0;
        int rechts = a.length - 1;
        int v = 0;

        while (links <= rechts)
        {
            int mitte = (links + rechts) / 2;

            v++; // == Vergleich
            if (a[mitte] == suchzahl)
            {
                return v;
            }

            v++; // < Vergleich
            if (suchzahl < a[mitte])
            {
                rechts = mitte - 1;
            }
            else
            {
                links = mitte + 1;
            }
        }

        return v;
    }

Die lokale Variable v zählt alle Vergleiche mit, die während der Suche anfallen. Die Methode vergleicheBinaer() liefert nicht den Index des gesuchten Elements (oder -1) zurück, sondern die Anzahl der notwendigen Vergleiche zum Finden der Suchzahl bzw. für die Feststellung des Nichtvorhandenseins derselben.

Die Methode für die lineare Suche ist dagegen recht einfach:

    public int vergleicheLinear(int[] a, int suchzahl)
    {
        int v = 0;

        for (int i = 0; i < a.length; i++)
        {
            v++; // == Vergleich
            if (a[i] == suchzahl)
            {
                return v;
            }
        }

        return v;
    }

Schauen wir uns nun noch die eigentliche Test-Routine an:

    public void vergleiche()
    {
        int summeBinaer = 0;
        int summeLinear = 0;

        for (int i = 1; i <= 250; i++)
        {
            summeBinaer += vergleicheBinaer(zahlen, i);
            summeLinear += vergleicheLinear(zahlen, i);
        }

        System.out.println("Summe Vergleiche (1..250):");
        System.out.println("Lineare Suche = " + summeLinear);
        System.out.println("Binäre  Suche = " + summeBinaer);
    }

Die beiden Suchverfahren werden jeweils 250 mal durchlaufen, für die Suchzahlen von 1 bis 250. Die Zahl der Vergleiche wird aufaddiert und dann ausgegeben.

Betrachten wir nun die ersten Zeilen der Klasse LinearVsBinaer:

public class LinearVsBinaer
{
    private int[] zahlen = ArrayTools.erzeugeArray(100);

    public LinearVsBinaer()
    {
        ArrayTools.fuelleArrayMitZufallszahlen(zahlen, 100, 1, 250);
        ArrayTools.selectionSortTeilarray(zahlen, 100);
        ArrayTools.zeigeArray(zahlen);
        vergleiche();
    }

    public static void main(String[] args)
    {
        new LinearVsBinaer();
    }    

Zum Erzeugen, Befüllen und Sortieren des Arrays werden Methoden aus der selbstgeschriebenen Utility-Klasse ArrayTools verwendet. Danach ruft der Konstruktor die Test-Methode vergleiche() auf. Das Array, das hier untersucht wird, besteht aus 100 zufälligen und aufsteigend sortierten int-Zahlen mit Werten zwischen 1 und 250.

Kommen wir nun zu den Ergebnissen des Programms:

    3    6   13   14   15   16   21   24   33   36
   38   41   43   43   46   50   50   56   57   59
   59   61   64   64   64   66   68   68   75   77
   80   81   83   84   92   92   94  101  105  105
  107  109  116  116  117  121  122  127  130  130
  131  145  145  146  146  153  156  156  159  159
  161  172  178  180  180  186  187  188  189  190
  190  197  197  198  210  213  217  217  220  220
  221  223  224  226  228  229  234  235  236  240
  241  243  244  244  246  246  246  248  249  250

Summe Vergleiche (1..250):
Lineare Suche = 21071
Binäre  Suche = 3086

Wenn wir das Programm noch einmal starten, werden andere Zufallszahlen erzeugt. Hier das Ergebnis eines zweiten Durchlaufs:

    3    4    8    8   10   16   17   27   31   32
   32   33   34   34   36   42   43   44   46   52
   55   59   59   60   63   64   65   66   69   72
   72   74   77   81   83   83   85   91   94   96
   98   99  104  105  107  109  111  115  116  121
  126  126  128  128  129  129  134  138  139  142
  143  143  152  154  164  167  169  173  174  176
  178  179  179  184  187  199  200  203  208  208
  211  212  213  213  213  213  215  221  221  222
  228  230  230  233  234  236  239  241  241  250

Summe Vergleiche (1..250):
Lineare Suche = 20818
Binäre  Suche = 3078

Beim ersten Durchlauf war die binäre Suche 6,83 mal schneller als die sequentielle, beim zweiten Durchlauf 6,76 mal schneller.

Offensichtlich ist die binäre Suche bei 100 Zahlen zirka fast sieben mal schneller als die sequentielle Suche, wenn man ein Array aus int-Zahlen durchsucht.

Testprogramm

Das oben erwähnte Testprogramm können Sie sich hier als Java-Quelltext herunterladen und selbst ausprobieren. Das Programm greift auf Methoden meiner selbst erstellten Utility-Klasse ArrayTools zu. Den Quelltext dieser Klasse können Sie sich ebenfalls hier herunterladen.

Erweitert man das Programm so, dass 1000 Zahlen erzeugt und durchsucht werden, ändert sich das Verhältnis von linearer zu binärer Suche drastisch:

Summe Vergleiche (1..2500):
Lineare Suche = 2082197
Binäre  Suche = 47046

Hier ist die binäre Suche ca. 44 mal schneller als die sequentielle. Auch ein zweiter Durchlauf ergab hier den Faktor 44.

Etwas Mathematik

Jetzt müssen wir doch noch wieder etwas mathematischer werden. Während der Zeitaufwand für die lineare Suche linear wächst: O(n), ist der Zeitaufwand für die binäre Suche ein logarithmischer: O(log(N)). Das liegt an der Halbierung des Suchraums bei jedem Schleifendurchgang.

Hier eine von ChatGPT erstellte Tabelle, die zeigt, wie die binäre Suche immer mehr an Vorteil gewinnt, je größer das zu durchsuchende Array ist:

N 100 1.000 10.000 100.000
Vergleiche linear 50,5 500,5 5.000,5 50.000,5
Vergleiche binär 8 11 15 18
Vorteil binär (Faktor) 6,3 45,5 333,4 2.777,8

Für die Vergleiche hat ChatGPT eine durchschnittliche Verteilung der Zufallszahlen in den sortierten Arrays angenommen.

Das Zeitverhalten der binären Suche O(log(N)) bezieht sich auf den Zweier-Logarithmus. Für solche Angaben ist es aber völlig egal, ob ein Zweier- , ein Zehner- oder ein natürlicher Logarithmus gemeint ist.

Trotzdem können wir uns die Sache noch einmal selbst anschaulich verdeutlichen:

N 16 32 64 128
N/2 8 16 32 64
log2(N) 4 5 6 7
Vorteil binär (Faktor) 2,00 3,20 5,33 9,14

Ein Suchalgorithmus mit dem Zeitverhalten O(log(N)) gewinnt immer mehr an Vorteil gegenüber einem Algorithmus mit einem O(N)-Zeitverhalten, je größer N ist.

6.3.4 Binäre Suchbäume und B-Bäume

Das auf dieser Seite betrachtete binären Suchverfahren eignet sich sehr gut für bereits sortierte Arrays oder andere Listen. Der zentrale Vorteil des Verfahrens liegt in seiner Effizienz: Durch das wiederholte Halbieren des Arrays kann ein gesuchtes Element in logarithmischer Zeit gefunden werden. Diese Effizienz ist jedoch an eine wesentliche Voraussetzung gebunden – die Daten müssen bereits sortiert vorliegen und dürfen sich während der Suche nicht verändern.

Was aber, wenn die sortierten Daten ständig durch Einfügen neuer Daten und Löschen nicht mehr benötigter Daten durcheinander gebracht werden? Große Datenbanken können nicht nach jeder Bearbeitung neu sortiert werden, das wäre viel zu aufwendig, und der Vorteil, den die binäre Suche mit sich bringt, wäre wieder zunichte gemacht. Speichert man die Daten dagegen in einem binären Suchbaum, hat man diese Probleme nicht.

Binäre Suchbäume übertragen das Grundprinzip der binären Suche – also das schrittweise Vergleichen und Eingrenzen des Suchbereichs – auf eine dynamische Datenstruktur. Die Ordnung der gespeicherten Werte liegt dabei nicht wie bei einem sortierten Array einfach als feste Reihenfolge vor, sondern ergibt sich aus der Anordnung der Knoten im Baum. Dadurch können Suchen, Einfügen und Löschen von Daten effizient durchgeführt werden, ohne dass die gesamte Struktur jedes Mal neu sortiert werden muss.

Aufgabe

Informieren Sie sich auf den Seiten, die ich für die Stufe Q1 geschrieben habe, was man unter einem solchen binären Suchbaum versteht, wie man ihn Element für Element aufbaut und wie man die Elemente in aufsteigend geordneter Weise mit dem sogenannten Inorder-Verfahren wieder auslesen kann.

Binäre Suchbäume auf den Seiten der Stufe Q1/Q2

Wenn Sie die oben verlinkten Seiten gründlich durchgearbeitet haben, dann werden Sie jetzt vielleicht enttäuscht sein, dass diese binären Suchbäume fast ausschließlich nur in Informatik-Lehrbüchern für Schulen und Hochschulen vorkommen. In der realen Welt verwendet man diese Art von Bäumen so gut wie gar nicht.

Für sehr große Datenmengen, insbesondere wenn diese nicht vollständig im Hauptspeicher gehalten werden können, stoßen einfache binäre Suchbäume nämlich an ihre Grenzen. Hier kommen die von Rudolf Bayer und Edward McCreight Anfang der 70er Jahre entwickelten B-Bäume ins Spiel. Diese B-Bäume erweitern das Konzept des Suchbaums, so dass auch in externen Speichern wie Festplatten oder SSDs effizient gesucht werden kann. B-Bäume bilden sozusagen das Fundament moderner Datenbank- und Dateisysteme.

Aufgabe

Informieren Sie sich auf den Seiten, die ich für die Stufe Q1 geschrieben habe, was man unter einem solchen B-Baum versteht und wie man ihn Element für Element aufbaut.

B-Bäume auf den Seiten der Stufe Q1/Q2

Seitenanfang
weiter mit der Sprung-, Index- und Interpolationssuche ...