Q1 Suchen und Sortieren

Suchen: iterativ und rekursiv

Lösung geprüft

Die Aufgabe der heutigen Stunde ist Suchen – iterativ und rekursiv! Fünf Teilaufgaben, und diesmal geht es nicht mehr nur um Arrays, sondern auch um die lineare Liste mit ihren toFirst()-, hasAccess()- und next()-Methoden. Die kommt im Abi ständig vor, deshalb lohnt es sich, das Muster einmal richtig zu verstehen.

Die Aufgabenstellung lautet

1 In einem Musikverwaltungsprogramm können Musiktitel organisiert und abgespielt werden. Die Musiktitel werden in einer linearen Liste gespeichert. a) Implementieren Sie die Methode boolean titelVorhanden(String pTitel, String pInterpret), die true zurückgibt, falls der durch die Parameter gegebene Musiktitel in der Liste vorkommt. b) Analysieren Sie die Methode methode1, indem Sie ihre Funktionsweise beschreiben.

2 Rechnerarbeit Implementieren Sie die gegebene Methodendokumentation: boolean pruefe(boolean[] ergebnisse). Return: true, falls mindestens ein positives Testergebnis im Array vorkommt. Ansonsten false.

3 Ein Logistikunternehmen verfügt über zwei Lager. Beim Zusammenstellen einer Bestellung wird die Ware aus einem der Lager entnommen. Anhand der Artikelnummer sind die Waren eindeutig zu identifizieren. Implementieren Sie suche(Artikelnummer : int) : boolean.

4 Gegeben ist die Liste von Quadratzahlen: 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121, 144. Führen Sie den Algorithmus der binären Suche auf der Zahlenreihe aus, indem Sie dokumentieren, wie sich links, rechts und mitte ändern. Notieren Sie auch die Methodenaufrufe mit Parametern. a) Suchen Sie nach der Zahl 100. b) Suchen Sie nach der Zahl 10.

5 Der Algorithmus der binären Suche lässt sich auch iterativ implementieren. Die Anweisungen innerhalb der Wiederholungsschleife sind durcheinandergeraten. Bringen Sie den Quelltext in die richtige Reihenfolge und ergänzen Sie gegebenenfalls Klammerungen.

Aufgabe 1 – Das Musikverwaltungsprogramm

Das Muster für lineare Listen

Bevor es losgeht: fast jede Aufgabe mit einer linearen Liste sieht gleich aus. Man merkt sich diese vier Zeilen und kommt damit sehr weit:

liste.toFirst();                   // an den Anfang springen
while (liste.hasAccess()) {        // solange man auf einem Element steht
    Musiktitel mt = liste.getContent();   // aktuelles Element holen
    // ... hier passiert die eigentliche Arbeit ...
    liste.next();                  // ein Element weiter
}
flowchart TD
    A["gefunden = false"] --> B["liste.toFirst(), Zeiger auf das erste Element"]
    B --> C{"liste.hasAccess() UND gefunden == false?"}
    C -- nein --> Z["return gefunden"]
    C -- ja --> D{"liste.getContent() gleich Suchschlüssel?"}
    D -- WAHR --> E["gefunden = true"]
    D -- FALSCH --> F["liste.next(), ein Element weiter"]
    E --> F
    F --> C
Wie man eine lineare Liste von vorne durchgeht

hasAccess() ist dabei das Entscheidende: es sagt, ob der Zeiger überhaupt auf einem Element steht. Ist man hinten rausgelaufen, liefert es false und die Schleife endet. Vergisst man liste.next(), läuft die Schleife ewig – das ist der häufigste Fehler bei diesen Aufgaben.

a) titelVorhanden

Musikverwaltungsprogramm.java
/* meininfokurs.cmrg.site */
/**
 *
 * Suche in einer linearen Liste
 *
 * @version 1.0 vom 14.09.2025
 * @meininfokurs.cmrg.site
 */

public boolean titelVorhanden(String pTitel, String pInterpret) {
    liste.toFirst();

    while (liste.hasAccess()) {
        Musiktitel mt = liste.getContent();

        if (mt.getTitel().equals(pTitel)
                && mt.getInterpret().equals(pInterpret)) {
            return true;              // gefunden, sofort raus
        }

        liste.next();
    }

    return false;                     // ganze Liste durch, nichts gefunden
}

Das ist eine lineare Suche auf einer Liste – man muss von vorne durchgehen, weil es bei einer Liste keinen Index gibt, mit dem man in die Mitte springen könnte. Binäre Suche ist auf einer linearen Liste also gar nicht möglich, selbst wenn sie sortiert wäre.

Wichtig: Strings vergleicht man mit .equals() und nicht mit ==. Das == prüft bei Objekten, ob es dasselbe Objekt im Speicher ist – nicht, ob derselbe Text drinsteht. Bei Strings aus Benutzereingaben geht das fast immer schief, und zwar ohne Fehlermeldung. Das Programm findet dann einfach nie etwas.

b) Was methode1 macht

methode1(String pGenre) geht die ganze Liste durch und sammelt alle Musiktitel ein, deren Genre mit dem übergebenen Genre übereinstimmt. Diese hängt sie an eine neue Liste liste2 an und gibt sie am Ende zurück.

Mit anderen Worten: sie filtert die Musiksammlung nach Genre. Ein besserer Name wäre titelNachGenre oder filterGenre – und genau darauf zielt die Aufgabe ab. Man soll merken, dass methode1 ein nichtssagender Name ist und dass man die Funktion trotzdem aus dem Code herauslesen kann.

Zwei Details, die man beim Analysieren erwähnen sollte: die Originalliste wird nicht verändert, es entsteht eine zweite. Und wenn kein Titel passt, kommt eine leere Liste zurück – nicht null. Das ist gut so, weil der Aufrufer dann ohne Sonderprüfung damit weiterarbeiten kann.

Aufgabe 2 – pruefe

/**
 * Die Testergebnisse im Array ergebnisse sollen ueberprueft werden.
 *
 * @param ergebnisse ein Array vom Typ boolean
 * @return true, falls mindestens ein positives Testergebnis vorkommt,
 *         ansonsten false
 */
public boolean pruefe(boolean[] ergebnisse) {
    for (int i = 0; i < ergebnisse.length; i++) {
        if (ergebnisse[i]) {
            return true;
        }
    }
    return false;
}

Wieder das Muster der linearen Suche: beim ersten Treffer sofort true zurückgeben, und erst wenn alles durchlaufen ist, false.

Beachte if (ergebnisse[i]) ohne Vergleich. Der Eintrag ist schon ein boolean, man muss ihn nicht erst mit true vergleichen. if (ergebnisse[i] == true) funktioniert zwar auch, ist aber umständlich – und wer sich dabei vertippt und = statt == schreibt, hat einen Fehler, den man schwer sieht.

Aufgabe 3 – Die Logistik mit zwei Lagern

public boolean suche(int Artikelnummer) {
    if (sucheInLager(lager1, Artikelnummer)) {
        return true;
    }
    return sucheInLager(lager2, Artikelnummer);
}

// Hilfsmethode, damit der Code nicht zweimal dasteht
private boolean sucheInLager(List<Artikel> lager, int Artikelnummer) {
    lager.toFirst();
    while (lager.hasAccess()) {
        if (lager.getContent().getArtikelnummer() == Artikelnummer) {
            return true;
        }
        lager.next();
    }
    return false;
}

Der Kniff hier ist die Hilfsmethode. Man könnte die Suchschleife zweimal hinschreiben, einmal für lager1 und einmal für lager2 – das wären dann zwei fast identische Blöcke, und wenn man später einen Fehler findet, muss man ihn an zwei Stellen beheben.

Möglich ist das, weil lager1 und lager2 denselben Typ haben. Die Hilfsmethode bekommt einfach die Liste als Parameter übergeben.

Und hier steht == statt .equals() – das ist richtig so, weil die Artikelnummer ein int ist und kein String. Bei einfachen Datentypen vergleicht == tatsächlich die Werte.

Aufgabe 4 – Binäre Suche auf den Quadratzahlen

Index[0][1][2][3][4][5][6][7][8][9][10][11]
Wert149162536496481100121144

a) Die Suche nach der 100

Aufruflinksmitterechtsa[mitte]Folge
binaereSuche(100, 0, 11)05113636 < 100 → rechts bleibt, links = 6
binaereSuche(100, 6, 11)68118181 < 100 → links = 9
binaereSuche(100, 9, 11)91011121121 > 100 → rechts = 9
binaereSuche(100, 9, 9)999100gefunden → true

Vier Aufrufe. Der letzte ist der wichtige: links und rechts sind beide 9, der Bereich besteht also nur noch aus einem Element – und das ist der gesuchte Wert.

b) Die Suche nach der 10

Aufruflinksmitterechtsa[mitte]Folge
binaereSuche(10, 0, 11)05113636 > 10 → rechts = 4
binaereSuche(10, 0, 4)02499 < 10 → links = 3
binaereSuche(10, 3, 4)3341616 > 10 → rechts = 2
links (3) > rechts (2) → Bereich leer, return false

Die 10 ist keine Quadratzahl, also kann sie gar nicht drin sein. Der Algorithmus engt trotzdem sauber ein und landet genau in der Lücke zwischen 9 und 16.

Aufgabe 5 – Die Zeilen sortieren

Java
/* meininfokurs.cmrg.site */
/**
 *
 * Binaere Suche, iterativ - die Zeilen in der richtigen Reihenfolge
 *
 * @version 1.0 vom 14.09.2025
 * @meininfokurs.cmrg.site
 */

public boolean binaereSuche_iterativ(int[] a, int i) {
    int links, mitte, rechts;
    links = 0;
    rechts = a.length - 1;

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

        if (a[mitte] == i) {
            return true;
        }
        if (a[mitte] < i) {
            links = mitte + 1;
        }
        if (a[mitte] > i) {
            rechts = mitte - 1;
        }
    }

    return false;
}

Warum genau diese Reihenfolge

  1. mitte = (int)((rechts + links) / 2); muss ganz oben in der Schleife stehen. Erst wenn die Mitte für den aktuellen Bereich berechnet ist, kann man dort hineinschauen.
  2. if (a[mitte] == i) return true; kommt als Nächstes. Trifft man den Wert, ist man fertig und braucht die anderen Vergleiche nicht mehr.
  3. if (a[mitte] < i) links = mitte + 1; – der gesuchte Wert liegt rechts, also rückt die linke Grenze nach.
  4. if (a[mitte] > i) rechts = mitte - 1; – umgekehrt.

Die ergänzten Klammerungen sind die geschweiften Klammern nach jedem if und die Klammern um den ganzen Schleifenrumpf. Bei einzeiligen if-Anweisungen darf man sie in Java weglassen, aber genau dann passiert der Klassiker: man fügt später eine zweite Zeile hinzu und die gehört plötzlich nicht mehr zum if.

Das (int) vor der Division ist überflüssig, weil rechts und links beide int sind und die Division damit sowieso abschneidet. Es steht so in der Vorlage, schadet nicht und macht die Absicht sogar deutlicher.

Aufgabe suchen

Tippe los. Strg+K öffnet die Suche von überall.

Zuletzt angesehen

Werbung