Dijkstra im Graph

Wave

Mitglied
Ich habe mit Hilfe des Schulbuch (Klett Gym, Informatik 4, S. 127) versucht, den Dijkstra-Algorithmus umzusetzen.
In der Schule haben wir noch keine Listen gelernt. Die Aufgabe soll mit Feldern so weit wie möglich gelöst werden und ArrayList sind auch erlaubt.
Leider funktioniert mein Code noch nicht.
Bei der Ausgabe kommt noch nicht der Wert für die kürzeste Entfernung raus.

Wie kann ich die Ausgabe der kürzesten Entfernungen mir anzeigen lassen und auch die Reihenfolge der Knoten vom Start bis zum Ziel ausgeben lassen? Bei mir bricht der Code noch nicht ab, wenn ich den Zielknoten erreicht habe.

Im Programmcode ist das Attribut istBesucht nur für die Breitensuche gedacht. Für Dijkstra sollte es nicht notwendig sein???


Danke.

Java:
public class Knoten{
    
    private String bezeichnung;
    private boolean istBesucht;
    private Knoten vorgaenger;
    private int pfadgewicht;
    
    public Knoten(String neueBezeichnung){
        bezeichnung = neueBezeichnung;
    }
    
    public String bezeichnungGeben(){
        return bezeichnung;
    }
    
    public void bezeichnungSetzen(String neueBezeichnung){
        bezeichnung = neueBezeichnung;
    }
    
    public boolean istBesuchtGeben(){
        return istBesucht;
    }
    
    public void istBesuchtSetzen(boolean neuIstBesucht){
        istBesucht = neuIstBesucht;
    }
    
    public Knoten vorgaengerGeben(){
        return vorgaenger;
    }
    
    public void vorgaengerSetzen(Knoten neuerVorgaenger){
        vorgaenger = neuerVorgaenger;
    }
    
    public int pfadgewichtGeben(){
        return pfadgewicht;
    }
    
    public void pfadgewichtSetzen(int neuesPfadgewicht){
        pfadgewicht = neuesPfadgewicht;
    }
}


Code:
import java.util.*;

public class Graph{

    private Knoten[] knotenfeld;
    private int[][] adjazenzmatrix;
    private int maxAnzahl;
    private int aktAnzahl;
    
    public Graph(int neueMaxAnzahl){
        knotenfeld = new Knoten[neueMaxAnzahl];
        adjazenzmatrix = new int[neueMaxAnzahl][neueMaxAnzahl];
        maxAnzahl = neueMaxAnzahl;
        aktAnzahl = 0;
    }
    
    public Knoten[] knotenfeldGeben(){
        return knotenfeld;
    }
    
    public int[][] adjazenzmatrixGeben(){
        return adjazenzmatrix;
    }
    
    public void knotenEinfuegen(Knoten k){
        if(aktAnzahl < maxAnzahl){
            knotenfeld[aktAnzahl] = k;
            aktAnzahl++;
        }
        else{
            System.out.println("Fehler! Es kann kein Knoten mehr eingefuegt werden.");
        }
    }
    
    public void knotenEinfuegen2(Knoten k){
        if (aktAnzahl < maxAnzahl){
            boolean istEingefuegt = false;
            int index = 0;
            while ((index < maxAnzahl) && (!istEingefuegt)){
                if (knotenfeld[index] == null){
                    knotenfeld[index] = k;
                    istEingefuegt = true;
                }
                else{
                    index++;
                }
            }
            aktAnzahl++;
        }
        else{
            System.out.println("Fehler! Es kann kein Knoten mehr eingefuegt werden.");
        }
    }
    
    public void kanteHinzufuegen(int startindex, int zielindex, int wert){
        if(startindex < 0 || zielindex < 0 || startindex >= aktAnzahl || zielindex >= aktAnzahl){
            System.out.println("Fehler! Falscher Index. Die Kante kann nicht hinzugefuegt werden.");
        }
        else{
            adjazenzmatrix[startindex][zielindex] = wert;
        }
    }
  
    public void kanteEntfernen(int startindex, int zielindex){
        if(adjazenzmatrix[startindex][zielindex] == 0 || startindex >= aktAnzahl || zielindex >= aktAnzahl){
            System.out.println("Fehler! Die Kante kann nicht entfernt werden.");
        }
        else{
            adjazenzmatrix[startindex][zielindex] = 0;
        }
    }
    
    public void alleKantenEntfernen(){
        for(int i = 0; i < maxAnzahl; i++){
            for(int j = 0; j < maxAnzahl; j++){
                adjazenzmatrix[i][j] = 0;
            }
        }
    }
    
    public int knotenindexSuchen(Knoten k){
        int index = -1;
        int i = 0;
        while(index < 0 && i < knotenfeld.length){
            if(knotenfeld[i].equals(k)){
                index = i;
            }
            else{
                i++;
            }
        }
        if(index < 0){
            System.out.println("Fehler! Der Knoten wurde nicht gefunden.");
        }
        return index;
    }
    
    public int knotenindexSuchen2(String name){
        int index = -1;
        int i = 0;
        while(index < 0 && i < knotenfeld.length){
            if(knotenfeld[i].bezeichnungGeben().equals(name)){
                index = i;
            }
            else{
                i++;
            }
        }
        if(index < 0){
            System.out.println("Fehler! Der Knoten wurde nicht gefunden.");
        }
        return index;
    }
    
    public void kanteHinzufuegen2(String start, String ziel, int wert){
        int startindex = knotenindexSuchen2(start);
        int zielindex = knotenindexSuchen2(ziel);
        kanteHinzufuegen(startindex, zielindex, wert);
    }
        
    public void knotenEntfernen(String name){
        int knotenindex = knotenindexSuchen2(name);
        if(knotenindex < 0){
            System.out.println("Fehler! Der Knoten konnte nicht entfernt werden.");
        }
        else{
            for(int i = 0; i < aktAnzahl; i++){
                adjazenzmatrix[knotenindex][i] = 0;
                adjazenzmatrix[i][knotenindex] = 0;
            }
            knotenfeld[knotenindex] = null;
        }   
    }   
    
    public void adjazenzmatrixAusgeben(){
        System.out.print("  ");
        for(int i = 0; i < aktAnzahl; i++){
            System.out.print("  " + i + "  ");
        }
        System.out.println("  ");
        for(int i = 0; i < aktAnzahl; i++){
            System.out.print(i + " ");
            for(int j = 0; j < aktAnzahl; j++){
                System.out.print(" " + adjazenzmatrix[i][j] + " ");
            }
            System.out.println();
        }
    }
    
    public void knotenfeldAusgeben(){
        System.out.println("Knotendaten:");
        for(int i = 0; i < aktAnzahl; i++){
            System.out.println(knotenfeld[i].bezeichnungGeben());
            System.out.println();
        }
    }
    
    public void dijkstraAusgeben(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{
            for(int i = 0; i < aktAnzahl; i++){
                if(i == startindex){
                    knotenfeld[startindex].pfadgewichtSetzen(0);
                    knotenfeld[startindex].vorgaengerSetzen(null);
                    knotenfeld[startindex].istBesuchtSetzen(false);
                }
                else{
                    knotenfeld[i].pfadgewichtSetzen(Integer.MAX_VALUE);
                    knotenfeld[i].vorgaengerSetzen(null);
                    knotenfeld[i].istBesuchtSetzen(false);   
                }
            } 
        }
        ArrayList<Integer> warteschlange = new ArrayList<Integer>();    // Warteschlange fuer die Knoten (Speichern der Indizes)
        for(int i = 0; i < aktAnzahl; i++){
            warteschlange.add(i);  // Hinzufuegen aller Knoten
        }
        
        // knotenfeld[startindex].istBesuchtSetzen(true);  // Startknoten auf "besucht" setzen
        
        while(!warteschlange.isEmpty()){
            int aktiverKnotenindex = warteschlange.remove(0);
            for(int j = 0; j < aktAnzahl; j++){
                if(adjazenzmatrix[aktiverKnotenindex][j] >= 0){
                    relaxationAusfuehren(aktiverKnotenindex, j);
                }
            }
            System.out.println("Pfadgewicht: " + knotenfeld[aktiverKnotenindex].pfadgewichtGeben());
        }
    }
    
    public void relaxationAusfuehren(int uIndex, int vIndex){
        int uGewicht = knotenfeld[uIndex].pfadgewichtGeben();
        int vGewicht = knotenfeld[vIndex].pfadgewichtGeben();
        int kantengewicht = adjazenzmatrix[uIndex][vIndex];
        if(vGewicht > uGewicht + kantengewicht){
            knotenfeld[vIndex].pfadgewichtSetzen(uGewicht + kantengewicht);
            knotenfeld[vIndex].vorgaengerSetzen(knotenfeld[uIndex]);
        } 
    }
}


Code:
public class Testablauf{
        
    private Graph g;
    
    public void ablaufen(){
        
        g = new Graph(5);   // Der Graph hat 5 Knoten
        
        Knoten k1 = new Knoten("A");
        Knoten k2 = new Knoten("B");
        Knoten k3 = new Knoten("C");
        Knoten k4 = new Knoten("D");
        Knoten k5 = new Knoten("E");
        
        g.knotenEinfuegen(k1);  // Index 0
        g.knotenEinfuegen(k2);  // Index 1
        g.knotenEinfuegen(k3);  // Index 2
        g.knotenEinfuegen(k4);  // Index 3
        g.knotenEinfuegen(k5);  // Index 4
        
        g.kanteHinzufuegen(0, 1, 3);    // A-B
        g.kanteHinzufuegen(1, 0, 3);
        g.kanteHinzufuegen(0, 2, 4);    // A-C
        g.kanteHinzufuegen(2, 0, 4);
        g.kanteHinzufuegen(0, 4, 1);    // A-E
        g.kanteHinzufuegen(4, 0, 1);
        g.kanteHinzufuegen(1, 2, 2);    // B-C
        g.kanteHinzufuegen(2, 1, 2);
        g.kanteHinzufuegen(2, 3, 1);    // C-D
        g.kanteHinzufuegen(3, 2, 1);
        g.kanteHinzufuegen(3, 4, 5);    // D-E
        g.kanteHinzufuegen(4, 3, 5);
        
        g.dijkstraAusgeben("A", "D");
    }
}
 

mihe7

Top Contributor
Leider funktioniert mein Code noch nicht.
Dein Algorithmus ist ja auch falsch.

https://de.wikipedia.org/wiki/Dijkstra-Algorithmus hat gesagt.:
  • Weise allen Knoten die beiden Eigenschaften (Attribute) „Distanz“ und „Vorgänger“ zu. Initialisiere die Distanz im Startknoten mit 0 und in allen anderen Knoten mit ∞
    {\displaystyle \infty }
    .
  • Solange es noch unbesuchte Knoten gibt, wähle darunter denjenigen mit minimaler (aufsummierter) Distanz aus und ...

Du musst in jeder Iteration erst einmal den Knoten mit der geringsten Distanz wählen.
 

Wave

Mitglied
Thanks.

In meiner Methode dijkstraAusgeben(..) weise ich in der ersten for-Anweisungen Pfadgewichte und Vorgänger allen Knoten zu.
Stimmt dieser Schritt?

Wo und wie soll ich in jeder Interation den Knoten mit der gerinsten Distanz wählen? Ich verstehe deine Anmerkung nicht. In welchen Zeilen muss ich was und wie ergänzen?
 

mihe7

Top Contributor
Hast Du Dir den Algorithmus unter dem genannten Wikipedia-Link angesehen?
1722419043646.png

Das ist das eigentlich recht gut erklärt.
 

Wave

Mitglied
Wenn ich mit "Wiki" weitergekommen wäre, dann hätte ich hier auch nicht gefragt.
Ich komme alleine und mit Wiki leider nicht weiter und finde den/ die Fehler in meine Code nicht.
Wenn du mir keine Hilfe geben willst (außer dem Verweis auf Wiki), dann vielen Dank. Entschuldigung dass ich kostbare Zeit in Anspruch genommen habe.
Ich habe freundlich um Hilfe gebeten.
 

KonradN

Super-Moderator
Mitarbeiter
Wenn ich mit "Wiki" weitergekommen wäre, dann hätte ich hier auch nicht gefragt.
Hier wäre wäre erst einmal die Frage: Woran scheitert es denn? (Es ist hier Hilfe zur Selbsthilfe!) In dem WIkipedia Beitrag ist ein Pseudo-Code gegeben. Den kannst Du doch 1:1 umsetzen. Dazu müsstest Du nicht einmal die Beschreibung verstanden haben.

Die Initialisierung könnte richtig sein, aber was direkt auffällt ist im Pseudo Code:
[I]u[/I]:= Knoten in [I]Q[/I] mit kleinstem Wert in abstand[]

Du hast bei der Knotenauswahl aber:
int aktiverKnotenindex = warteschlange.remove(0);

Du nimmst also einfach den ersten Knoten aus der Warteschlange. (Warteschlange bei Dir ist das Q im Wikipedia Artikel)

Das ist also der erste Fehler, den Du beheben musst.

Aber auch das
Code:
 6          für jeden Nachbarn v von u:
 7              falls v in Q:                            // falls noch nicht berechnet
sehe ich nicht in deinem Code. Hier werden nur dann Knoten genommen, die noch in der Warteschlange sind.

Evtl. hilft es, Deinen Code etwas umzustrukturieren, so dass Du es mehr so abbildest, wie es im Pseudocode genannt ist. Und dann fügst Du als Kommentare überall ein, was Du da (vom Pseudocode) umgesetzt hast. Versuche das doch einmal und zeige uns dann, wie weit Du kommst. Dann schauen wir gerne drüber um mögliche Fehler zu finden.
 

Wave

Mitglied
Jetzt kommt allerdings beim Testen eine Endlosschleife heraus.

Java:
    public void dijkstraAusgeben(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{
            for(int i = 0; i < aktAnzahl; i++){
                if(i == startindex){
                    knotenfeld[startindex].pfadgewichtSetzen(0);
                    knotenfeld[startindex].vorgaengerSetzen(null);
                    knotenfeld[startindex].istBesuchtSetzen(false);
                }
                else{
                    knotenfeld[i].pfadgewichtSetzen(Integer.MAX_VALUE);
                    knotenfeld[i].vorgaengerSetzen(null);
                    knotenfeld[i].istBesuchtSetzen(false);   
                }
            }
            
            ArrayList<Integer> warteschlange = new ArrayList<Integer>();    // Warteschlange fuer die Knoten (Speichern der Indizes)
            for(int i = 0; i < aktAnzahl; i++){
                warteschlange.add(i);  // Hinzufuegen aller Knoten
            }
            
            int aktiverKnotenindex = startindex;
            while(!warteschlange.isEmpty() && aktiverKnotenindex != zielindex){
                for(int j = 0; j < aktAnzahl; j++){
                    int kantengewicht = adjazenzmatrix[aktiverKnotenindex][j];
                    if(adjazenzmatrix[aktiverKnotenindex][j] >= 0){
                        int uGewicht = knotenfeld[aktiverKnotenindex].pfadgewichtGeben();
                        int vGewicht = knotenfeld[j].pfadgewichtGeben();
                        if(vGewicht > uGewicht + kantengewicht){
                            knotenfeld[j].pfadgewichtSetzen(uGewicht + kantengewicht);
                            knotenfeld[j].vorgaengerSetzen(knotenfeld[aktiverKnotenindex]);
                        }
                    }
                }
                warteschlange.add(aktiverKnotenindex);
                System.out.println("Aus der Warteschlange entnommener Knoten mit dem Index: " + aktiverKnotenindex + ".");
                
                System.out.println("Pfadgewicht: " + knotenfeld[aktiverKnotenindex].pfadgewichtGeben());     
            }
        }
    }
 

KonradN

Super-Moderator
Mitarbeiter
Java:
                warteschlange.add(aktiverKnotenindex);
                System.out.println("Aus der Warteschlange entnommener Knoten mit dem Index: " + aktiverKnotenindex + ".");
Du fügst etwas hinzu und gibst aus, dass du etwas entnommen hast ... Sieht also erst einmal dubios aus.

Und die Prüfung isEmpty ist natürlich auch wenig sinnvoll, wenn man keine Elemente entfernt.

Im Augenblick verstehe ich auch nicht, was für Vorgaben Du versuchst umzusetzen. Der Vorschlag mit dem Pseudo-Code vom wiki Eintrag scheint Dir zumindest nicht zu gefallen.... Aber das limitiert ggf. die mögliche Unterstützung durch uns.
 

KonradN

Super-Moderator
Mitarbeiter
Dann Bau das doch als Code um. Und hier gilt auch der Hinweis: Nimm die Vorgaben als Kommentare in den Code. Und dann wirst Du relativ einfach die Abweichungen sehen.

Mache Dir auch klare Kommentare, was wie notiert / gespeichert wird. Ich sehe da bei dem Diagramm:
  • Markierung als besucht bei Knoten
  • Speichern des Abstandes
  • Was muss der Status vorab sein - Evtl. brauchst Du eine Initialisierung

Ansonsten scheint es mir, dass Du einen Mix hast aus diesen Vorgaben und dem Pseudo Code aus dem Wiki Artikel.

Beispiel:
Wenn Du das Diagram ansiehst, dann fängt es dort mit einer leeren Warteschlange an, in der nur der Startknoten kommt. Da passt das Hinzufügen aller Knoten nicht.

Dann gibt es von der Umsetzung her gewisse Probleme, da Du hier jetzt keine Schleifen sondern nur Statusübergänge hast. Das müsstest Du entweder umformen oder Du implementierst es als eine State Machine, bei Du eine Ablaufsteuerung hast, die also auf einen Status etwas ausführt und dann den Folgestatus zurück bekommt. Das fängt beim Start Staus an und läuft so lange, bis Du in einem Fertig Status bist. Jeder Status hat dann im execute die Implementation, die im Kästchen genannt wurde. Das ist zwar in der Praxis so eher unüblich aber kann so eine Umsetzung relativ übersichtlich machen, da Du jedes Kästchen explizit so bauen und auch testen kannst.
 

mihe7

Top Contributor
Wenn ich mit "Wiki" weitergekommen wäre, dann hätte ich hier auch nicht gefragt.
Ich komme alleine und mit Wiki leider nicht weiter und finde den/ die Fehler in meine Code nicht.
Wenn du mir keine Hilfe geben willst (außer dem Verweis auf Wiki), dann vielen Dank. Entschuldigung dass ich kostbare Zeit in Anspruch genommen habe.
Ich habe freundlich um Hilfe gebeten.
Sorry, aber weder in Deinem ersten Post noch In Deiner Antwort hattest Du den Artikel erwähnt, so dass ich nicht wusste, ob Du a) den Artikel schon kennst bzw. b) den Link gesehen hast.

Was den Verweis auf externe Quellen betrifft, so hat das nichts damit zu tun, dass man Dir nicht helfen will, sondern schlicht mit der Tatsache, dass es bereits eine gute Beschreibung gibt und es völlig affig wäre, wenn ich Dir hier eine Erklärung gebe, die am Ende wahrscheinlich wesentlich schlechter ist.

Was Die Hilfe im Forum ganz allgemein betrifft: die meisten versuchen, Hilfe zur Selbsthilfe zu geben. Fertige Lösungen wirst Du hier eher nicht bekommen.

Nach diesem "Muster" soll der Dijkstra-Algorithmus umgesetzt werden.
Der dort skizzierte Algorithmus ist aber nur für einen Spezialfall gültig, nämlich dann, wenn die Entfernung aller benachbarter Knoten konstant 1 (bzw. eine beliebige andere Konstante) ist. Im Algorithmus ist die Entfernung also schlicht die Anzahl an Kanten vom Startknoten aus.

Bei der Breitensuche werden erst alle Knoten mit der gleichen Entfernung (Anzahl an Kanten) zum Startknoten untersucht. Um einen Knoten aus der Nachbarschaft zu erreichen, wird eine Kante mehr benötigt (-> Entfernung + 1). Wenn aber ein Knoten der Nachbarschaft bereits besucht wurde, dann wurde diesem bereits eine Entfernung zugewiesen, die zwangsweise kleiner sein muss. Daher werden diese Knoten überhaupt nicht mehr berücksichtigt.

Das Problem ist, dass es im Allgemeinen keinen Zusammenhang zwischen Entfernungen (Kantengewichte) und Anzahl der Kanten gibt. Dennoch bleibt die Grundidee des Dijkstra-Algorithmus erhalten: "Die Grundidee des Algorithmus ist es, immer derjenigen Kante zu folgen, die den kürzesten Streckenabschnitt vom Startknoten aus verspricht" (Wikipedia) Ein weiterer Punkt ist, dass bei beiden Algorithmen die Entfernung eines jeden besuchten Knotens zum Startknoten bereits optimal ist.

Für den allgemeinen Fall wird also keine Breitensuche durchgeführt, stattdessen wird in jeder Iteration der Knoten mit der jeweils geringsten Entfernung zum Startknoten ge- und besucht. Die Ermittlung eben dieses Knotens fehlte bei Dir in Deinem ersten Post. "Besuchen" bedeutet hier, den Vorgängerknoten zu setzen, die Entfernungen der noch nicht besuchten Nachbarknoten zu aktualisieren und natürlich den Knoten als "besucht" zu markieren. Dieses Markieren geschieht im Pseudocode des Wikipedia-Artikels implizit durch Entfernen des Knotens aus der Menge der noch nicht besuchten Knoten Q.

Nachdem unklar ist, welchen der beiden Algorithmen Du jetzt eigentlich umsetzen willst, belasse ich es mal dabei. Ferner gilt, was @KonradN bereits alles geschrieben hat.
 

Wave

Mitglied
Danke.
Ist in meiner Methode dijkstraAusgeben(...) alles bis zu while korrekt? Bis hier her habe ich ja auch die Knoten initialisiert (Gewicht, Pfadlänge) und in der Warteschlange stehen alles Knoten mit den Indizes.

Mit

int aktiverKnotenindex = startindex;

habe ich dann den Index des Startknotens.
Diesen muss ich dann aus der Warteschlange entfernen (richtig)?

In Wiki was du gezeigt hast, steht:
1 Funktion Dijkstra(Graph, Startknoten):
2 initialisiere(Graph,Startknoten,abstand[],vorgänger[],Q)
3 solange Q nicht leer: // Der eigentliche Algorithmus
4 u:= Knoten in Q mit kleinstem Wert in abstand[]
5 entferne u aus Q // für u ist der kürzeste Weg nun bestimmt
6 für jeden Nachbarn v von u:
7 falls v in Q: // falls noch nicht berechnet
8 distanz_update(u,v,abstand[],vorgänger[]) // prüfe Abstand vom Startknoten zu v
9 return vorgänger[]


Zeile 2 und 3 habe ich umgesetzt, oder?

Wegen Zeile 4 und 5 komme ich immer noch nicht weiter:
Müsste ich
warteschlange.remove(aktiverKnotenindex)

ergänzen?
Dann würde der Index aus der ArrayList entfernt werden, den ich abgearbeitet habe?
 

Barista

Top Contributor
Nach diesem "Muster" soll der Dijkstra-Algorithmus umgesetzt werden.
Im Ablaufdiagramm fällt mir auf, dass "aktueller Knoten" auftaucht, ohne vorher definiert worden zu sein.

Letztens wurde hier auch eine Aufgabe diskutiert, deren Originaltext ich unverständlich (falsch?!?) fand.

Nach meinem Empfinden liegt oft das Problem bereits in der Aufgabenstellung, der Tutor will es den Schülern eventuell schwer machen oder verhindern, dass KI benutzt wird.

Eventuell liegt es aber am Tutor.
 

mihe7

Top Contributor
Zeile 2 und 3 habe ich umgesetzt, oder?
Ja.

Ich beziehe mit auf den Code aus Kommentar #7

Wegen Zeile 4 und 5 komme ich immer noch nicht weiter:
Müsste ich
warteschlange.remove(aktiverKnotenindex)
Letzteres wäre Schritt 5. Zuerst musst Du aktiverKnotenindex ermitteln, d. h. Du musst den Index des noch nicht besuchten Knotens mit dem kleinsten Pfadgewicht finden. Hierzu bietet sich eine eigene Methode an. Dort kannst Du einfach über alle Knoten der Warteschlange iterieren und merkst Dir dabei, welcher Index das bislang kleinste Gewicht "liefert" (das bislang kleinste Gewicht brauchst Du für den Vergleich). Am Ende gibst Du den Index zurück.

Die Schritte 4 und 5 sehen dann in etwa so aus:
Java:
int aktiverKnotenindex = sucheKnotenMitKleinstemPfadgewicht();
warteschlange.remove(aktiverKnotenIndex);
 

mihe7

Top Contributor
Die Schritte 4 und 5 sehen dann in etwa so aus:
Java:
int aktiverKnotenindex = sucheKnotenMitKleinstemPfadgewicht();
warteschlange.remove(aktiverKnotenIndex);
Nachtrag: ich habe gerade gesehen, dass warteschlange eine List ist. Da funktioniert das remove in der Form nicht, weil die Methode mit int überladen ist (und dann den Index des zu löschenden Eintrags in der Liste erwartet).

1722507911874.png

D. h. man muss dem Compiler explizit mitteilen, dass die Methode remove(Object) verwendet werden soll, um den Eintrag mit dem Wert aktiverKnotenIndex zu entfernen:
Java:
warteschlange.remove( (Object) aktiverKnotenIndex );

Um das zu verdeutlichen, nehmen wir mal eine ArrayList<Integer> an, die wie folgt aufgebaut ist:
IndexWert
01
13

Dann führt ein remove(3) zu einer IndexOutOfBoundsException, ein remove(1) würde die zweite Zeile entfernen (Zeile mit Index 1) und ein remove( (Object) 1 ) die erste Zeile (Zeile mit dem Wert 1).
 
Zuletzt bearbeitet:

Wave

Mitglied
Kannst du mir Rückmeldung bitte geben, @mihe7? DANKE! Die Methode läuft ohne Fehler, jedoch ist die Ausgabe sicher falsch. Ich beziehe mich hier nur noch auf den folgenden Programmcode und versuche nur noch den Pseudocode aus Wiki zu verwenden (in de r Schule habe wir leider andere Bezeichnung usw., daher komme ich stark durcheinander).
Deinen Vorschlag, die Methode sucheKnotenMitKleinstemPfadgewicht() auszulagern konnte ich nicht umsetzen, da außerhalb der Methode dijkstraAusgeben(...) das Attribut warteschlange bei mir dann nicht bekannt ist???


Java:
public void dijkstraAusgeben(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{
            for(int i = 0; i < aktAnzahl; i++){
                if(i == startindex){
                    knotenfeld[startindex].pfadgewichtSetzen(0);
                    knotenfeld[startindex].vorgaengerSetzen(null);
                    knotenfeld[startindex].istBesuchtSetzen(false);
                }
                else{
                    knotenfeld[i].pfadgewichtSetzen(Integer.MAX_VALUE);
                    knotenfeld[i].vorgaengerSetzen(null);
                    knotenfeld[i].istBesuchtSetzen(false);   
                }
            }
            
            ArrayList<Integer> warteschlange = new ArrayList<Integer>();    // Warteschlange fuer die Knoten (Speichern der Indizes)
            for(int i = 0; i < aktAnzahl; i++){
                warteschlange.add(i);  // Hinzufuegen aller Knoten
            }
            
            int aktiverKnotenindex = startindex;
            while(!warteschlange.isEmpty() && aktiverKnotenindex != zielindex){
                for(int i = 0; i < warteschlange.size(); i++){
                    if(knotenfeld[warteschlange.get(i)].pfadgewichtGeben() < knotenfeld[warteschlange.get(Integer.valueOf(aktiverKnotenindex))].pfadgewichtGeben()){
                        aktiverKnotenindex = i;   
                    }
                }
                warteschlange.remove(Integer.valueOf(aktiverKnotenindex));
                
                for(int j = 0; j < aktAnzahl; j++){
                    int kantengewicht = adjazenzmatrix[aktiverKnotenindex][j];
                    if(adjazenzmatrix[aktiverKnotenindex][j] > 0){
                        int uGewicht = knotenfeld[aktiverKnotenindex].pfadgewichtGeben();
                        int vGewicht = knotenfeld[j].pfadgewichtGeben();
                        if(vGewicht > uGewicht + kantengewicht){
                            knotenfeld[j].pfadgewichtSetzen(uGewicht + kantengewicht);
                            knotenfeld[j].vorgaengerSetzen(knotenfeld[aktiverKnotenindex]);
                        }
                    }
                
                }
                //System.out.println("Aus der Warteschlange entnommener Knoten mit dem Index: " + aktiverKnotenindex + ".");
                
                System.out.println("Pfadgewicht: " + knotenfeld[aktiverKnotenindex].pfadgewichtGeben());     
            }
        }
    }
 

Barista

Top Contributor
Deinen Vorschlag, die Methode sucheKnotenMitKleinstemPfadgewicht() auszulagern konnte ich nicht umsetzen, da außerhalb der Methode dijkstraAusgeben(...) das Attribut warteschlange bei mir dann nicht bekannt ist???

Bei 'warteschlange' handelt es sich nicht um ein Attribut, sondern um eine Variable. Ein Attribut ist ein Feld einer Klasse.

Wenn die Variable warteschlange in der anzulegenden Methode nicht bekannt ist, kann man die Variable über einen Parameter an die Methode übergeben.

Einen speziellen Kommentar 'suche Knoten mit kleinstem Pfadgewicht' hast Du auch nicht gemacht.

Entweder war Dir der Hinweis von KonradN mit den Kommentaren egal oder Du hast den Hinweis nicht verstanden.

Sind eben auch eine Menge Infos.

Ich habe mal in einem Projekt eine fachliche Anforderung umgesetzt.

Da war eine Satz drin, den ich nicht verstanden hatte.

Den habe ich ausgeblendet, ist wahrscheinlich so eine Psychosache.

Später hat mich der Fachverantwortliche gefragt, ob ich den Satz umgesetzt hätte.

Ich hätte besser fragen sollen.

Manchmal ist das aber auch schwierig, man wird als dumm hingestellt.

Manche Fachverantwortliche in Firmen oder Behörden können sich nach vielen Jahren dort gar nicht mehr vorstellen, dass es noch eine Welt da draußen gibt und man ihre Welt nicht kennt.
 

mihe7

Top Contributor
Deinen Vorschlag, die Methode sucheKnotenMitKleinstemPfadgewicht() auszulagern konnte ich nicht umsetzen, da außerhalb der Methode dijkstraAusgeben(...) das Attribut warteschlange bei mir dann nicht bekannt ist???
Dazu hat @Barista schon alles geschrieben. Du kannst die lokale Variable warteschlange als Argument an die Methode übergeben, wenn diese einen entsprechenden Parameter anbietet...

Deine Schleife findet aber nicht das gewünschte Element. Falls Du die Suche besonders optimal umsetzen wolltest, dann wäre das ein schönes Beispiel für: schreib den Code so stupide und einfach wie möglich (KISS - keep it simple and stupid).

Ansonsten schauen wir uns mal an, was hier passiert: Du suchst einen Knoten in der List warteschlange, dessen Pfadgewicht kleiner als das Pfadgewicht des "aktiven" Knotens (Knoten mit dem Index aktiverKnotenIndex im knotenfeld) ist. Der aktive Knoten ist zu Beginn der Startknoten. Das Pfadgewicht des Startknotens ist aber 0, d. h. so lange es keine negativen Pfadgewichte gibt, wirst Du nie einen anderen Knoten finden.

Hinzu kommt, dass Du hier den Index der Warteschlange und den Index des Knotens im knotenfeld miteinander vermischst.

Daher wirklich stupide umsetzen:
Dort kannst Du einfach über alle Knoten der Warteschlange iterieren und merkst Dir dabei, welcher Index das bislang kleinste Gewicht "liefert" (das bislang kleinste Gewicht brauchst Du für den Vergleich). Am Ende gibst Du den Index zurück.
Java:
// Liefert den Listenindex(!) des Knotens in knotenliste mit minimalen Pfadgewicht
private int sucheKnotenMitKleinstemPfadgewicht(List<Integer> knotenliste) {
    int minListIndex = 0;
    int minPfadgewicht = knotenfeld[knotenliste.get(minListIndex)].gibPfadgewicht();
    for (int i = 1; i < knotenliste.size(); i++) {
        int aktuellerKnotenIndex = knotenliste.get(i);
        int aktuellesPfadgewicht = knotenfeld[aktuellerKnotenIndex].gibPfadgewicht();
        if (aktuellesPfadgewicht < minPfadgewicht) {
            minPfadgewicht = aktuellesPfadgewicht;
            minListIndex = i;
        }
    }
    return minListIndex;
}

Damit (Achtung: jeglichen Code von mir im Forum als Skizze verstehen, wenn nicht ausdrücklich anders gekennzeichnet - ich tippe das Zeug heir nur im Editor rein) kannst Du jetzt in Deiner while-Schleife aufrufen:
Java:
int warteschlangenIndex = sucheKnotenMitKleinstemPfadgewicht(warteschlange);
int aktiverKnotenIndex = warteschlange.get(warteschlangenIndex);
warteschlange.remove(warteschlangenIndex);

EDIT: aktuellerKnotenIndex in aktiverKnotenIndex umbenannt
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
D Dijkstra Algorithmus Hilfe!! Java Basics - Anfänger-Themen 9
U Meinung zum Dijkstra Algorithmus Java Basics - Anfänger-Themen 6
U Dijkstra Algorithmus Laufzeit Java Basics - Anfänger-Themen 3
S Dijkstra-Algoritmus Java Basics - Anfänger-Themen 7
M Dijkstra Algorithmus in Graphen auf mehrere verschiedene Knoten anwenden lassen Java Basics - Anfänger-Themen 11
S Dijkstra Algorithmus funktioniert nicht Java Basics - Anfänger-Themen 4
S GraphNode --- Dijkstra Algorithmus : NullPointerException Java Basics - Anfänger-Themen 1
Binary.Coder Tipp für Ein-/Ausgabe für Dijkstra Java Basics - Anfänger-Themen 6
K Dijkstra implementierung 2.0 Java Basics - Anfänger-Themen 19
B PriorityQueue im dijkstra Algorithmus implementieren Java Basics - Anfänger-Themen 4
T Dijkstra auf adjazenzmatrix Java Basics - Anfänger-Themen 7
Q Tiefensuche Graph -> Schulprojekt Java Basics - Anfänger-Themen 1
F Graph Tiefensuche Methode Java Basics - Anfänger-Themen 7
S Längster Pfad zwischen zwei Vertices in einem Graph Java Basics - Anfänger-Themen 3
danieldemetry Java - Graph Komponenten - Ausgabe Java Basics - Anfänger-Themen 0
M Untersuchen ob ein Graph nach entfernen einer Kante immer noch zusammenhängend ist Java Basics - Anfänger-Themen 70
O ADT Graph nach größe Abfragen Java Basics - Anfänger-Themen 42
N gerichteter Graph aus einer Datei einlesen Java Basics - Anfänger-Themen 21
Z Graph einlesen Java Basics - Anfänger-Themen 2
S Ungerichteter Graph in Java Java Basics - Anfänger-Themen 1
M int double int double Graph Java Basics - Anfänger-Themen 3
A Tiefensuche in Graph Java Basics - Anfänger-Themen 4
N gerichteten Graph abspeichern Java Basics - Anfänger-Themen 2
Luk10 Frage zu Graph Tiefensuche Java Basics - Anfänger-Themen 4
S Methoden Wegsuche in einem Graph Java Basics - Anfänger-Themen 6
F Zusammenhängend Komponente suchen(Graph) Java Basics - Anfänger-Themen 4
F Kanten in Graph Java Basics - Anfänger-Themen 3
M Wth? übernimmt nichtübergebenen Wert (Graph) Java Basics - Anfänger-Themen 4
T Wie kann ich einem Graph in nem JPanel eine fixe Größe geben? Java Basics - Anfänger-Themen 6
H gerichteter Graph Java Basics - Anfänger-Themen 9
B Graph aus 2dim-Array Java Basics - Anfänger-Themen 3

Ähnliche Java Themen

Neue Themen


Oben