|
@@ -0,0 +1,128 @@
|
|
|
+package Algorithms;
|
|
|
+
|
|
|
+import java.util.ArrayList;
|
|
|
+
|
|
|
+import Model.LayeredGraphEdge;
|
|
|
+import Model.LayeredGraphNode;
|
|
|
+
|
|
|
+
|
|
|
+/**
|
|
|
+ * Der aus der Vorlesung bekannte Sweep Algorithmus zur Minnimierung von Kantenkreuzungen
|
|
|
+ * Es wird immer genau ein sweep durchgeführt
|
|
|
+ * @author kolja
|
|
|
+ *
|
|
|
+ */
|
|
|
+public class SweepCrossingMinimizer {
|
|
|
+
|
|
|
+
|
|
|
+ public void minimizeCrossings( LayeredGraphNode graph ) {
|
|
|
+ ArrayList< ArrayList< LayeredGraphNode > > layers = graph.getContainedLayers();
|
|
|
+ System.out.println( "Number of Detected Crossings before minimization: " + numberOfCrossings( layers ) );
|
|
|
+ for( int i = 1; i < layers.size(); i++ )
|
|
|
+ { // Gehe alle Layer durch
|
|
|
+ ArrayList<LayeredGraphNode> l1 = layers.get( i - 1 );
|
|
|
+ ArrayList<LayeredGraphNode> l2 = layers.get( i );
|
|
|
+ graph.setOrderedLayer( reduceCrossingsBetweenLayers( l1, l2, false ), i ); // minnimiere die Kreuzungen zwischen den letzten beiden Layern
|
|
|
+ }
|
|
|
+ for( int i = layers.size() - 2; i >= 0; i-- )
|
|
|
+ { // Gehe alle Layer rückwärts durch
|
|
|
+ ArrayList<LayeredGraphNode> l1 = layers.get( i + 1 );
|
|
|
+ ArrayList<LayeredGraphNode> l2 = layers.get( i );
|
|
|
+ graph.setOrderedLayer( reduceCrossingsBetweenLayers( l1, l2, true ), i ); // minnimiere die Kreuzungen zwischen den letzten beiden Layern
|
|
|
+ }
|
|
|
+ System.out.println( "Number of Detected Crossings after minimization: " + numberOfCrossings( layers ) );
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Minnimiert die Kantenkreuzungen zwischen zwei layern
|
|
|
+ * @param l1 Eine geordnete Liste mit Knoten aus dem ersten Layer
|
|
|
+ * @param l2 Eine geordnete Liste mit Knoten aus dem zweiten Layer
|
|
|
+ * @param rev Gibt an, in welche Richtung die Kanten verlaufen (true, falls von l2 nach l1)
|
|
|
+ * @return Gibt eine Liste mit Gewichten zurück, nach denen die Knoten sortiert werden sollen
|
|
|
+ */
|
|
|
+ private ArrayList<Double> reduceCrossingsBetweenLayers( ArrayList<LayeredGraphNode> l1, ArrayList<LayeredGraphNode> l2, boolean rev)
|
|
|
+ {
|
|
|
+ ArrayList< Double > gewicht = new ArrayList< Double >();
|
|
|
+ for( LayeredGraphNode n : l2 )
|
|
|
+ { // Für jeden Knoten in Layer 2
|
|
|
+ ArrayList< LayeredGraphEdge > edges = null;
|
|
|
+ if( rev )
|
|
|
+ edges = n.getOutgoingEdges();
|
|
|
+ else
|
|
|
+ edges = n.getIncomingEdges(); // Kanten nach Layer 1
|
|
|
+ double g = 0;
|
|
|
+ for( LayeredGraphEdge e : edges )
|
|
|
+ { // Ermittle das Gewicht des Knotens
|
|
|
+ if( rev )
|
|
|
+ g += l1.indexOf( e.getTargets().get( 0 ) );
|
|
|
+ else
|
|
|
+ g += l1.indexOf( e.getSources().get( 0 ) );
|
|
|
+ }
|
|
|
+ g /= edges.size(); // Teile das Gewicht durch die Anzahl der Kanten
|
|
|
+ gewicht.add( g );
|
|
|
+ }
|
|
|
+ return gewicht;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Zählt die Anzahl der Kantenkreuzungen in einem Graph
|
|
|
+ * @param layers Eine Liste mit Sortierten Layern
|
|
|
+ * @return Die Anzahl der Kreuzungen
|
|
|
+ */
|
|
|
+ private int numberOfCrossings(ArrayList<ArrayList<LayeredGraphNode>> layers)
|
|
|
+ {
|
|
|
+ ArrayList<LayeredGraphNode> lastLayer = null;
|
|
|
+ int crossings = 0;
|
|
|
+ for( ArrayList<LayeredGraphNode> l : layers )
|
|
|
+ {
|
|
|
+ if( lastLayer != null )
|
|
|
+ crossings += numberOfCrossings( lastLayer, l);
|
|
|
+ lastLayer = l;
|
|
|
+ }
|
|
|
+ return crossings;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * Zählt die Anzahl der Kantenkreuzungen zwischen zwei Layern (Es wird angenommen dass alle Kanten von l1 nach l2 verlaufen)
|
|
|
+ * @param l1 Der erste Layer
|
|
|
+ * @param l2 Der zweite Layer
|
|
|
+ * @return Die Anzahl der Kreuzungen
|
|
|
+ */
|
|
|
+ private int numberOfCrossings( ArrayList<LayeredGraphNode> l1, ArrayList<LayeredGraphNode> l2 )
|
|
|
+ {
|
|
|
+ // Algoritmus aus der Vorlesung
|
|
|
+ ArrayList< Integer > serie = new ArrayList<>();
|
|
|
+ for( LayeredGraphNode n : l1 )
|
|
|
+ {
|
|
|
+ ArrayList<LayeredGraphEdge> edges = n.getOutgoingEdges();
|
|
|
+ int i = 0;
|
|
|
+ for( LayeredGraphNode n2 : l2 )
|
|
|
+ {
|
|
|
+ for( LayeredGraphEdge e : edges )
|
|
|
+ {
|
|
|
+ if( e.getTargets().contains( n2 ) )
|
|
|
+ {
|
|
|
+ serie.add( i );
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ i++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ int crossings = 0;
|
|
|
+ for( int i = 1; i < serie.size(); i++ )
|
|
|
+ {
|
|
|
+ if( serie.get( i ) < serie.get( i - 1 ) )
|
|
|
+ {
|
|
|
+ int j = i - 1;
|
|
|
+ for( ; j > 0 && serie.get( i ) < serie.get( j - 1 ) ; j-- );
|
|
|
+ crossings += i - j;
|
|
|
+ int v = serie.get( i );
|
|
|
+ serie.remove( i );
|
|
|
+ serie.add( j, v);
|
|
|
+ i = Math.max( 1, j );
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return crossings;
|
|
|
+ }
|
|
|
+}
|