
// Klasse AbstractGraph

   /**
    * dfs-traversiert diesen Graphen. Gibt dabei Informationen
    * ber die besuchten Knoten und Kanten auf System.out aus.
    */
   public void printDfsTraverse() {
      boolean[] visited = new boolean[this.getNumberOfVertices()];
      java.util.Stack<java.util.Iterator<Graph.Edge>> s = new java.util.Stack<java.util.Iterator<Graph.Edge>>();
      for (int i = 0; i < this.getNumberOfVertices(); ++i) {
         if (!visited[i]) {
            System.out.println("Neuer dfs-Baum, Wurzel:");
            System.out.println("Knoten           " + getVertexLabel(i) + "[" + i + "]");
            visited[i] = true;
            s.push(this.edgeIterator(i));
            do {
               if (s.peek().hasNext()) {
                  Graph.Edge currentEdge = s.peek().next();
                  int toVertex = currentEdge.getToVertex();
                  if (!visited[toVertex]) {
                     for (int j = 0; j < s.size(); ++j) System.out.print("   ");
                     System.out.println("Baumkante:    " +
                                        getVertexLabel(currentEdge.getFromVertex()) + 
                                        "[" + currentEdge.getFromVertex() + "] -> " +
                                        getVertexLabel(toVertex) + "[" + toVertex + "]");
                     for (int j = 0; j < s.size(); ++j) System.out.print("   ");
                     System.out.println("Knoten           " + getVertexLabel(toVertex) + "[" + toVertex + "]");
                     visited[toVertex] = true;
                     s.push(this.edgeIterator(toVertex));
                  } else {
                     for (int j = 0; j < s.size(); ++j) System.out.print("   ");
                     System.out.println("Andere Kante: " +
                                        getVertexLabel(currentEdge.getFromVertex()) + 
                                        "[" + currentEdge.getFromVertex() + "] -> " +
                                        getVertexLabel(toVertex) + "[" + toVertex + "]");
                  }
               } else {
                  s.pop();
               }
            } while(!s.isEmpty());
         }
      }
   }

   /**
    * bfs-traversiert diesen Graphen. Gibt dabei Informationen
    * ber die besuchten Knoten und Kanten auf System.out aus.
    */
   public void printBfsTraverse() {
      int[] level = new int[this.getNumberOfVertices()];
      java.util.Arrays.fill(level, -1);
      java.util.Queue<Integer> vertexQueue = new java.util.LinkedList<Integer>();
      for (int i = 0; i < this.getNumberOfVertices(); ++i) {
         if (level[i] == -1) {
            level[i] = 0;
            vertexQueue.add(i);
            System.out.println("Neuer bfs-Baum, Wurzel:");
            System.out.println("Knoten           " + getVertexLabel(i) + "[" + i + "]");
            do {
               for (java.util.Iterator<Graph.Edge> it = edgeIterator(vertexQueue.remove()); it.hasNext(); ) {
                  Graph.Edge currentEdge = it.next();
                  int fromVertex = currentEdge.getFromVertex();
                  int toVertex = currentEdge.getToVertex();
                  if (level[toVertex] == -1) {
                     for (int j = 0; j < level[fromVertex]; ++j) System.out.print("   ");
                     System.out.println("Baumkante:    " +
                                        getVertexLabel(fromVertex) + "[" + fromVertex + "] -> " +
                                        getVertexLabel(toVertex) + "[" + toVertex + "]");
                     for (int j = 0; j < level[fromVertex]; ++j) System.out.print("   ");
                     System.out.println("Knoten           " + getVertexLabel(toVertex) + "[" + toVertex + "]");
                     level[toVertex] = level[fromVertex] + 1;
                     vertexQueue.add(toVertex);
                  } else {
                     for (int j = 0; j < level[fromVertex]; ++j) System.out.print("   ");
                     System.out.println("Andere Kante: " +
                                        getVertexLabel(fromVertex) + "[" + fromVertex + "] -> " +
                                        getVertexLabel(toVertex) + "[" + toVertex + "]");
                  }
               }
            } while(!vertexQueue.isEmpty());
         }
      }
   }

   /**
    * Ermittelt, ob von einem bestimmten Knoten zu einem bestimmten Knoten
    * ein Weg bzw. eine Bahn existiert.
    *
    * @param  fromVertex der Startknoten.
    * @param  toVertex   der Endknoten.
    *
    * @return null falls kein Weg bzw. keine Bahn existiert,
    *         sonst eine Liste der Indizes der Knoten des Wegs bzw. der Bahn.
    *
    * @throws IndexOutOfBoundsException falls fromVertex oder toVertex auerhalb des zulssigen Bereichs liegt
    *                                   (0 .. getNumberOfVertices()-1).
    */
   public java.util.LinkedList<Integer> getPath(int fromVertex, int toVertex) {
      if (toVertex < 0 || this.getNumberOfVertices() <= toVertex) {
         // fromVertex wird automatisch unten geprft
         throw new IndexOutOfBoundsException("Knotenindex des Endknotens unzulssig");
      }
      if (fromVertex == toVertex) {
         // von einem Knoten zu sich selbst gibt es definitionsgem immer
         // einen Weg bzw. eine Bahn (selbst wenn es keine Schlinge gibt!)
         // Rckgabe-Knotenliste vertexList aufbauen
         java.util.LinkedList<Integer> vertexList = new java.util.LinkedList<Integer>();
         vertexList.add(fromVertex);
         return vertexList;
      }
      // bfs-Traversierung
      // dadurch ist sichergestellt, dass es keinen Weg bzw. keine Bahn mit
      //    weniger Kanten als den/die von uns gefundene/n geben kann
      // Startknoten der bfs-Traversierung = Startknoten des Wegs/der Bahn
      int[] predecessor = new int[this.getNumberOfVertices()];
      java.util.Arrays.fill(predecessor, -1);
      java.util.Queue<Integer> vertexQueue = new java.util.LinkedList<Integer>();
      predecessor[fromVertex] = -2;
      vertexQueue.add(fromVertex);
      do {
         for (java.util.Iterator<Graph.Edge> it = edgeIterator(vertexQueue.remove()); it.hasNext(); ) {
            Graph.Edge currentEdge = it.next();
            int fromVert = currentEdge.getFromVertex();
            int toVert = currentEdge.getToVertex();
            if (predecessor[toVert] == -1) {
               // Baumkante
               if (toVert == toVertex) {
                  // Weg bzw. Bahn gefunden!
                  // Rckgabe-Knotenliste vertexList anhand des Felds predecessor aufbauen
                  java.util.LinkedList<Integer> vertexList = new java.util.LinkedList<Integer>();
                  vertexList.addFirst(toVert);
                  do {
                     vertexList.addFirst(fromVert);
                     fromVert = predecessor[fromVert];
                  } while (fromVert != -2);
                  return vertexList;
               } else {
                  predecessor[toVert] = fromVert;
                  vertexQueue.add(toVert);
               }
            } // else Kante zu bereits besuchtem Knoten, wir tun nichts
         }
      } while(!vertexQueue.isEmpty());
      // Zielknoten liegt nicht in diesem bfs-spannenden Baum =>
      // Zielknoten ist vom Startknoten aus nicht erreichbar
      return null;
   }

   /**
    * Gibt an, ob zwei Knoten (stark) zusammenhngend sind.
    *
    * @param  vertex1 der eine Knoten.
    * @param  vertex2 der andere Knoten.
    *
    * @throws IndexOutOfBoundsException falls vertex1 oder vertex2 auerhalb des zulssigen Bereichs liegt
    *                                   (0 .. getNumberOfVertices()-1).
    */
   public boolean connected(int vertex1, int vertex2) {
      return this.getPath(vertex1, vertex2) != null &&
             ((!this.directed()) || this.getPath(vertex2, vertex1) != null);
   }

