Breitensuche bis zu einem Knoten mit einem bestimmten Merkmal

Wave

Mitglied
Hallo,
wir haben die Methode breitensucheVonBis(start, ziel) gemeinsam entwickelt, die von einem bestimmten Startknoten mit der Breitensuche bis zu einem bestimmten Zielknoten geht.
Von diesem Code aufbauend (in der Schule zusammen gemacht), soll nun von einem Startknoten wieder mit der Breitensuche ein nächster erreichbarer Knoten gefunden werden, der zum ersten Mal eine bestimmte Eigenschaft besitzt, hier: beim Knoten soll Glasfaser verfügbar sein.

Die Bedingungen haben wir geändert, aber leider hört die Methode breitensucheAusfuehrenBisGlasfaser(start) nicht bei dem Knoten auf, an dem Glasfaser mit true gesetzt ist.
Der Zielindex ist ja von Beginn an noch nicht bekannt wie bei der Methode breitensucheVonBis(start, ziel). Daher: wie kann ich die Breitensuche dann abbrechen, wenn der erste Knoten mit Glasfaser erreicht wurde?
Kann bitte jemand weiterhelfen?


Von diesem Code sollen wir ausgehen:

Java:
    public void breitensucheVonBis(String start, String ziel){
        int startindex = knotenindexSuchen2(start);
        int zielindex = knotenindexSuchen2(ziel);
        if(startindex == -1 || zielindex == -1){
            System.out.println("Fehler! Der Startknoten oder der Zielknoten konnte nicht gefunden werden.");
        }
        else{
            knotenInitialisieren();
            ArrayList<Integer> warteschlange = new ArrayList<Integer>();    // Warteschlange fuer die Knoten (Speichern der Indizes)
            warteschlange.add(startindex);  // Hinzufuegen des Startknotens in die Warteschlange
            knotenfeld[startindex].istBesuchtSetzen(true);  // Startknoten auf "besucht" setzen
            System.out.println("Breitensuche: ");
            System.out.println("Knoten " + knotenfeld[startindex].bezeichnungGeben() + " besucht!");
            int aktiverKnotenindex = startindex;
            while(!warteschlange.isEmpty() && aktiverKnotenindex != zielindex){
                aktiverKnotenindex = warteschlange.remove(0);
                if(aktiverKnotenindex == zielindex){
                    System.out.println("Ziel gefunden!");
                }
                else{
                    for(int i = 0; i < aktAnzahl; i++){
                        if(adjazenzmatrix[aktiverKnotenindex][i] == true && !knotenfeld[i].istBesuchtGeben()){
                            knotenfeld[i].istBesuchtSetzen(true);
                            warteschlange.add(i);
                            System.out.println("Knoten " + knotenfeld[i].bezeichnungGeben() + " besucht!");
                        }
                    }
                }
            }
        }
    }


Hier der abgeänderte Code:

Code:
    public void breitensucheAusfuehrenBisGlasfaser(String start){
        int startindex = knotenindexSuchen2(start);
        if(startindex == -1){
            System.out.println("Fehler! Der Startknoten konnte nicht gefunden werden.");
        }
        else{
            knotenInitialisieren();
            ArrayList<Integer> warteschlange = new ArrayList<Integer>();    // Warteschlange fuer die Knoten (Speichern der Indizes)
            warteschlange.add(startindex);  // Hinzufuegen des Startknotens in die Warteschlange
            knotenfeld[startindex].istBesuchtSetzen(true);  // Startknoten auf "besucht" setzen
            System.out.println("Breitensuche: ");
            System.out.println("Knoten " + knotenfeld[startindex].bezeichnungGeben() + " besucht!");
            System.out.println("Glasfaser vorhanden: " + knotenfeld[startindex].hatGlasfaserGeben() + ".");
            int aktiverKnotenindex = startindex;
            while(!warteschlange.isEmpty() && !knotenfeld[aktiverKnotenindex].hatGlasfaserGeben()){
                aktiverKnotenindex = warteschlange.remove(0);
                if(knotenfeld[aktiverKnotenindex].hatGlasfaserGeben() == true){
                    System.out.println("Ziel gefunden!");
                }
                else{
                    for(int i = 0; i < aktAnzahl; i++){
                        if(adjazenzmatrix[aktiverKnotenindex][i] == true && !knotenfeld[i].istBesuchtGeben()){
                            knotenfeld[i].istBesuchtSetzen(true);
                            warteschlange.add(i);
                            System.out.println("Knoten " + knotenfeld[i].bezeichnungGeben() + " besucht!");
                            System.out.println("Glasfaser vorhanden: " + knotenfeld[i].hatGlasfaserGeben() + ".");
                        }
                    }
                }
            }
        }
    }
 
Danke, wo müsste dann die Ausgabe der besuchten Knoten dann eingefügt werden?

Es soll ja die Ausgabe die Form haben: "Startknoten, dann naechster Knoten, ..., Zielknoten".
 
Naja, in der while-Schleife findet der tatsächliche Besuch des Knotens statt... Verschieb die beiden Zeilen mal nach 17.
 
Danke.
Ich habe nun die Methode weitergeschrieben.
Sie soll immer noch folgendes machen: suche von einem Startknoten den erreichbaren Folgeknoten, bei dem Glasfaser verfügbar ist.
Mir ist aufgefallen, dass in meiner ersten Version die Methode einen Erfolg ausgibt, wenn auch der Startknoten bereits Glasfaser hat.
Es soll aber ein anderer Knoten, der nicht der Startknoten ist, mit der Eigenschaft Glasfaser gesucht werden.

Den Programmcode hänge ich unten an.
In Pseudocode habe ich mir folgendes gedacht:
  • Wenn der Startknoten Glasfaser hat, dann suche alle seine erreichbaren Nachbarknoten, führe von diesen dann die Breitensuche aus.
  • Wenn der Startknoten nicht Glasfaser hat, mache die Breitensuche ganz "normal" (das war der Code zu meinem Beginn des Beitrags).

Beim Testen ist nun folgendes geschehen:
Wenn der Startknoten Glasfaser hat, dann kommt die Ausgabe, dass der Startknoten Glasfaser hat. Die Nachbarknoten werden auch anscheinend gefunden. Aber dann macht die Breitensuche nicht mehr weiter.
Beim Debuggen führt er die nachfolgende while-Anweisung nicht weiter aus???
Die Blöcke mit System.out.println("XXX") und System.out.println("YYY") habe ich testweise eingefügt, und diese Blöcke werden auch erreicht. Nur es geht dann nicht weiter.

Wie kann ich das erreichen, dass der Algorithmus dann die Breitensuche weiter fortsetzt???
Vielen Dank!

Java:
    public void breitensucheAusfuehrenBisGlasfaser2(String start){
        int startindex = knotenindexSuchen2(start);
        boolean gefunden = false;
        
        if(startindex == -1){
            System.out.println("Fehler! Der Startknoten konnte nicht gefunden werden.");
        }
        else{
            knotenInitialisieren();
            ArrayList<Integer> warteschlange = new ArrayList<Integer>();    // Warteschlange fuer die Knoten (Speichern der Indizes)
            warteschlange.add(startindex);  // Hinzufuegen des Startknotens in die Warteschlange
            knotenfeld[startindex].istBesuchtSetzen(true);  // Startknoten auf "besucht" setzen
            System.out.println("Breitensuche: ");
            System.out.println("Knoten " + knotenfeld[startindex].bezeichnungGeben() + " besucht!");
            System.out.println("Glasfaser vorhanden: " + knotenfeld[startindex].hatGlasfaserGeben() + ".");
            int aktiverKnotenindex = startindex;
            if(knotenfeld[aktiverKnotenindex].hatGlasfaserGeben() == true){
                System.out.println("Diese Strasse hat bereits Glasfaser!");
                System.out.println("Suche nach der naechsten Strasse mit Glasfaser:");
                System.out.println("XXX");
                for(int i = 0; i < aktAnzahl; i++){
                    if(adjazenzmatrix[aktiverKnotenindex][i] == true && !knotenfeld[i].istBesuchtGeben()){
                        knotenfeld[i].istBesuchtSetzen(true);
                        warteschlange.add(i);
                        System.out.println("Knoten " + knotenfeld[i].bezeichnungGeben() + " besucht!");
                        System.out.println("Glasfaser vorhanden: " + knotenfeld[i].hatGlasfaserGeben() + ".");
                        System.out.println("YYY");
                    }
                }
                while(!warteschlange.isEmpty() && !knotenfeld[aktiverKnotenindex].hatGlasfaserGeben()){
                    aktiverKnotenindex = warteschlange.remove(0);
                    if(knotenfeld[aktiverKnotenindex].hatGlasfaserGeben() == true){
                        System.out.println("Ziel gefunden!");
                        gefunden = true;
                    }
                    else{
                        for(int i = 0; i < aktAnzahl; i++){
                            if(adjazenzmatrix[aktiverKnotenindex][i] == true && !knotenfeld[i].istBesuchtGeben()){
                                knotenfeld[i].istBesuchtSetzen(true);
                                warteschlange.add(i);
                                System.out.println("Knoten " + knotenfeld[i].bezeichnungGeben() + " besucht!");
                                System.out.println("Glasfaser vorhanden: " + knotenfeld[i].hatGlasfaserGeben() + ".");
                                System.out.println("ZZZ");
                            }
                        }
                    }
                }
                if(!gefunden){
                    System.out.println("Fehler! Kein Glasfaser gefunden!");
                }
            }
            else{
                while(!warteschlange.isEmpty() && !knotenfeld[aktiverKnotenindex].hatGlasfaserGeben()){
                    aktiverKnotenindex = warteschlange.remove(0);
                    if(knotenfeld[aktiverKnotenindex].hatGlasfaserGeben() == true){
                        System.out.println("Ziel gefunden!");
                        gefunden = true;
                    }
                    else{
                        for(int i = 0; i < aktAnzahl; i++){
                            if(adjazenzmatrix[aktiverKnotenindex][i] == true && !knotenfeld[i].istBesuchtGeben()){
                                knotenfeld[i].istBesuchtSetzen(true);
                                warteschlange.add(i);
                                System.out.println("Knoten " + knotenfeld[i].bezeichnungGeben() + " besucht!");
                                System.out.println("Glasfaser vorhanden: " + knotenfeld[i].hatGlasfaserGeben() + ".");
                            }
                        }
                    }
                }
                if(!gefunden){
                    System.out.println("Fehler! Kein Glasfaser gefunden!");
                }
            }
        }
    }
 
Huhu,
ich habe gerade noch etwas geändert

Ich habe nun "warteschlange.clear" eingefügt, damit der Startknoten weg ist (richtig?)
Vor while habe ich nun aktiverKnotenindex = warteschlange.get(0) gesetzt (richtig?).


Der neue Code:
Java:
    public void breitensucheAusfuehrenBisGlasfaser2(String start){
        int startindex = knotenindexSuchen2(start);
        boolean gefunden = false;
      
        if(startindex == -1){
            System.out.println("Fehler! Der Startknoten konnte nicht gefunden werden.");
        }
        else{
            knotenInitialisieren();
            ArrayList<Integer> warteschlange = new ArrayList<Integer>();    // Warteschlange fuer die Knoten (Speichern der Indizes)
            warteschlange.add(startindex);  // Hinzufuegen des Startknotens in die Warteschlange
            knotenfeld[startindex].istBesuchtSetzen(true);  // Startknoten auf "besucht" setzen
            System.out.println("Breitensuche: ");
            System.out.println("Knoten " + knotenfeld[startindex].bezeichnungGeben() + " besucht!");
            System.out.println("Glasfaser vorhanden: " + knotenfeld[startindex].hatGlasfaserGeben() + ".");
            int aktiverKnotenindex = startindex;
            if(knotenfeld[aktiverKnotenindex].hatGlasfaserGeben() == true){
                warteschlange.clear();
                System.out.println("Diese Strasse hat bereits Glasfaser!");
                System.out.println("Suche nach der naechsten Strasse mit Glasfaser:");
                System.out.println("XXX");
                for(int i = 0; i < aktAnzahl; i++){
                    if(adjazenzmatrix[aktiverKnotenindex][i] == true && !knotenfeld[i].istBesuchtGeben()){
                        knotenfeld[i].istBesuchtSetzen(true);
                        warteschlange.add(i);
                        System.out.println("Knoten " + knotenfeld[i].bezeichnungGeben() + " besucht!");
                        System.out.println("Glasfaser vorhanden: " + knotenfeld[i].hatGlasfaserGeben() + ".");
                        System.out.println("YYY");
                    }
                }
                aktiverKnotenindex = warteschlange.get(0);
                while(!warteschlange.isEmpty() && !knotenfeld[aktiverKnotenindex].hatGlasfaserGeben()){
                    aktiverKnotenindex = warteschlange.remove(0);
                    if(knotenfeld[aktiverKnotenindex].hatGlasfaserGeben() == true){
                        System.out.println("Ziel gefunden!");
                        gefunden = true;
                    }
                    else{
                        for(int i = 0; i < aktAnzahl; i++){
                            if(adjazenzmatrix[aktiverKnotenindex][i] == true && !knotenfeld[i].istBesuchtGeben()){
                                knotenfeld[i].istBesuchtSetzen(true);
                                warteschlange.add(i);
                                System.out.println("Knoten " + knotenfeld[i].bezeichnungGeben() + " besucht!");
                                System.out.println("Glasfaser vorhanden: " + knotenfeld[i].hatGlasfaserGeben() + ".");
                                System.out.println("ZZZ");
                            }
                        }
                    }
                }
                if(!gefunden){
                    System.out.println("Fehler! Kein Glasfaser gefunden!");
                }
            }
            else{
                while(!warteschlange.isEmpty() && !knotenfeld[aktiverKnotenindex].hatGlasfaserGeben()){
                    aktiverKnotenindex = warteschlange.remove(0);
                    if(knotenfeld[aktiverKnotenindex].hatGlasfaserGeben() == true){
                        System.out.println("Ziel gefunden!");
                        gefunden = true;
                    }
                    else{
                        for(int i = 0; i < aktAnzahl; i++){
                            if(adjazenzmatrix[aktiverKnotenindex][i] == true && !knotenfeld[i].istBesuchtGeben()){
                                knotenfeld[i].istBesuchtSetzen(true);
                                warteschlange.add(i);
                                System.out.println("Knoten " + knotenfeld[i].bezeichnungGeben() + " besucht!");
                                System.out.println("Glasfaser vorhanden: " + knotenfeld[i].hatGlasfaserGeben() + ".");
                            }
                        }
                    }
                }
                if(!gefunden){
                    System.out.println("Fehler! Kein Glasfaser gefunden!");
                }
            }
        }
    }
 
Zuletzt bearbeitet:
Evtl. hilft es Dir, wenn man Dir ein paar Handwerksmittel an die Hand gibt.

Eine komplexe, lange Methode zu überblicken ist schlicht schwer und fehleranfällig, Daher ist eines der Gebote in der Softwareentwicklung: KISS: Keep It Simple, Stupid.

Das bedeutet u.a., dass Du komplexe Dinge aufteilst ("Teile und Herrsche"). Statt einer Methode schreibst du dann mehrere Methoden. Und diese sollten dann auch direkt lesbar sein. Das ist dann eine einfache Umsetzung von Pseudocode.

Beispiel: Ein Pseudocode ist etwas wie:
Wenn startIndex ungültig: Brich ab

Java:
        if(!isIndexValid(startindex)) {
            System.out.println("Fehler! Der Startknoten konnte nicht gefunden werden.");
            return;
        }
a) Die Bedingung mit dem == -1 ist relativ trivial, aber die Lesbarkeit ist halt grösser, wenn man selbst sowas in eine Methode packt.
b) Wenn Du abbrechen willst: Dann geh raus aus der Methode oder wenn es ein Fehler ist, der nicht vorkommen dürfte: Wirf eine Exception um ganz abzubrechen. Das erspart Dir das else und damit den grossen weiteren Block.

Wie Du in Punkt b) schon sehen kannst: Halte die Verschachtelungstiefe gering. Harte Grenzen sind immer blöd, aber Du solltest da nie mehr wie 2 oder max 3 Einrückungen haben. Also in einer Schleife ein if => Zwei Einrückungen.

Dann kann man auch die Länge gut bewerten. Auch hier gibt es keine absoluten Werte, aber 5-10 Zeilen Code sind überschaubar. Alles andere nicht mehr. Also mach Methoden!

Ich habe mir den Code nicht im Detail angesehen um da jetzt ein wirkliches Refactoring machen zu können, aber ich hoffe, der Ansatz wird wirklich deutlich. Und ich kann immer nur empfehlen: Schreibe wirklich erst Pseudocode auf! Und denn dann auch einfach halten. Fang oberflächig an. Was muss gemacht werden? Dann sind die Punkte ggf. an sich hoch komplex a.la. Sammel alle Knoten mit Glasfaser in einer Warteschlange.

Dann hast Du das Problem beschrieben. Um a zu machen, musst Du machen:
  • a1
  • a2
  • a3

Um a1 zu machen, musst Du halt machen:
  • a1.1
  • a1.2
  • a1.3
...

Wenn Du es schon so aufgebaut hast, dann ist das schon fast fertig. Jeder einzelne Pseudocode wird einfach sein. Und die einzelnen Punkte muss man durchgehen, bis man dann eine Komplexität hat, die es trivial macht.

Das einfach nur als ganz allgemeiner Hinweis. Der nächste Ausbau wäre dann, dass man die Teilbereiche auch noch testet und so ... Aber das geht dann für das Forum zu weit....
 
Hi,
danke für den Text.
Ich bin Schüler, leider kann ich mit Excepton und einigen weiteren Tipps noch nicht viel angefangen (habe gerade nur ein bißchen was auf anderen Seiten angelesen). Haben wir noch nicht gelernt und alles kann ich sofrt nicht umsetzen/ lernen...
Ich bin Anfänger. Leider läuft der Informatik-Unterricht so ab, das der Lehrer die ganze Zeit mit seinem Handy spielt/ chatet, und wir alle irgendwelche Sachen sich selbst erarbeiten müssen. Daher bringe ich mir die Sachen selber bei und brauche jetzt Hilfe. Was da an den Schulen abgeht, ist leider eine andere Sache...

Es tut mir leid, wenn mein Code den Ansprüchen nicht genügt.

Ich habe den obigen Code nochmals etwas "veschlankt".
Du kannst mir gerne Rückmeldung geben, ob dies deinem Prinzip besser entspricht?

Hauptsächlich würde ich mich freuen, wenn meine ursprüngliche Frage weitergeholfen werden kann:

In Pseudocode:
  • Wenn der Startknoten Glasfaser hat, dann suche zuerst alle seine erreichbaren Nachbarknoten, führe von diesen dann die Breitensuche aus und suche den nächsten erreichbaren Nachbarknoten, bei dem Glasfaser möglich ist.
  • Wenn der Startknoten nicht Glasfaser hat, mache die Breitensuche ganz "normal" und suche den nächsten erreichbaren Nachbarknoten, bei dem Glasfaser möglich ist.

Lieben Dank!!!

Der "verschlankte" Code:

Java:
    public void breitensucheAusfuehrenBisGlasfaser3(String start){
        int startindex = knotenindexSuchen2(start);
        boolean gefunden = false;
        
        if(startindex == -1){
            System.out.println("Fehler! Der Startknoten konnte nicht gefunden werden.");
        }
        else{
            if(knotenfeld[startindex].hatGlasfaserGeben() == false){
                breitensucheAusfuehrenBisGlasfaser(start); 
            }
            else{
                knotenInitialisieren();
                ArrayList<Integer> warteschlange = new ArrayList<Integer>();    // Warteschlange fuer die Knoten (Speichern der Indizes)
                knotenfeld[startindex].istBesuchtSetzen(true);  // Startknoten auf "besucht" setzen
                System.out.println("Breitensuche: ");
                System.out.println("Knoten " + knotenfeld[startindex].bezeichnungGeben() + " besucht!");
                System.out.println("Glasfaser vorhanden: " + knotenfeld[startindex].hatGlasfaserGeben() + ".");
                System.out.println("Diese Strasse hat bereits Glasfaser!");
                System.out.println("Suche nach der naechsten Strasse mit Glasfaser:");
                System.out.println("XXX");
                for(int i = 0; i < aktAnzahl; i++){
                    if(adjazenzmatrix[startindex][i] == true && !knotenfeld[i].istBesuchtGeben()){
                        knotenfeld[i].istBesuchtSetzen(true);
                        warteschlange.add(i);
                        System.out.println("Knoten " + knotenfeld[i].bezeichnungGeben() + " besucht!");
                        System.out.println("Glasfaser vorhanden: " + knotenfeld[i].hatGlasfaserGeben() + ".");
                        System.out.println("YYY");
                    }
                }
                if(warteschlange.isEmpty()){
                    System.out.println("Fehler! Kein Glasfaser gefunden!");
                }
                else{
                    int aktiverKnotenindex = warteschlange.get(0);
                    while(!warteschlange.isEmpty() && !knotenfeld[aktiverKnotenindex].hatGlasfaserGeben()){
                        aktiverKnotenindex = warteschlange.remove(0);
                        if(knotenfeld[aktiverKnotenindex].hatGlasfaserGeben() == true){
                            System.out.println("Ziel gefunden!");
                            gefunden = true;
                        }
                        else{
                            for(int i = 0; i < aktAnzahl; i++){
                                if(adjazenzmatrix[aktiverKnotenindex][i] == true && !knotenfeld[i].istBesuchtGeben()){
                                    knotenfeld[i].istBesuchtSetzen(true);
                                    warteschlange.add(i);
                                    System.out.println("Knoten " + knotenfeld[i].bezeichnungGeben() + " besucht!");
                                    System.out.println("Glasfaser vorhanden: " + knotenfeld[i].hatGlasfaserGeben() + ".");
                                    System.out.println("ZZZ");
                                }
                            }
                        }
                    }
                    if(!gefunden){
                    System.out.println("Fehler! Kein Glasfaser gefunden!");
                    }
                }
            }
        }
    }
 
Es tut mir leid, wenn mein Code den Ansprüchen nicht genügt.
Ganz wichtig: Das war nur als freundlicher Hinweis gedacht. Es geht nicht um irgendwelche Ansprüche sondern darum, Dir zu helfen.

Und die Thematik (die man als "Clean Code" umschreiben würde) ist leider keine wirklich leichte und ohne "Führung" auch extrem schwer umzusetzen. Daher sieh es wirklich nicht als Kritik an!

Kannst Du evtl. einmal den ganzen Code, der notwendig ist zur Ausführung, posten? Wenn Du ihn aus Copyright Gründen nicht öffentlich posten willst, dann starte ein kurzes Gespräch mit mir und poste da den Code.

Dann würde ich mir am Wochenende versuchen die Zeit zu nehmen, ein paar Änderungen ("Refactoring" wäre da der gebräuchliche englische Begriff) zu machen und zu erläutern, wieso das gemacht wurde. Ich möchte Dir nicht zu viel versprechen, aber evtl. ist sowas ja von Interesse bzw. es hilft Dir, sowas in Zukunft umzusetzen.

Wenn die Unterstützung vom Lehrer fehlt: Evtl. kann man sowas auch zusammen in einer Art Lerngruppe machen?

Falls so etwas von Interesse ist, dann können wir die Möglichkeiten auch gerne im Gespräch erläutern.
 
In Pseudocode:
  • Wenn der Startknoten Glasfaser hat, dann suche zuerst alle seine erreichbaren Nachbarknoten, führe von diesen dann die Breitensuche aus und suche den nächsten erreichbaren Nachbarknoten, bei dem Glasfaser möglich ist.
  • Wenn der Startknoten nicht Glasfaser hat, mache die Breitensuche ganz "normal" und suche den nächsten erreichbaren Nachbarknoten, bei dem Glasfaser möglich ist.
Das Problem war ja Deine Schleife. Die läuft, bis ein Glasfaserknoten gefunden ist oder keine weiteren Knoten mehr in der Warteschlange sind. Wenn also der Startknoten ein Glasfaserknoten ist und Du den Startknoten in die Warteschlange legst, endet die Schleife sofort beim Startknoten.

Naheliegende Lösung: lege den Startknoten nicht in die Warteschlange.
 

Neue Themen


Zurück
Oben