diff --git a/src/graphvisualizer/containers/ContentResizerPane.java b/src/graphvisualizer/containers/ContentResizerPane.java
index aac1502..4c85b0d 100644
--- a/src/graphvisualizer/containers/ContentResizerPane.java
+++ b/src/graphvisualizer/containers/ContentResizerPane.java
@@ -32,57 +32,53 @@
import javafx.scene.transform.Scale;
/**
- *
* @author brunomnsilva
*/
public class ContentResizerPane extends Pane {
- private final Node content;
- private final DoubleProperty resizeFActor = new SimpleDoubleProperty(1);
+ private final Node content;
+ private final DoubleProperty resizeFActor = new SimpleDoubleProperty(1);
- public ContentResizerPane(Node content) {
- this.content = content;
+ public ContentResizerPane(Node content) {
+ this.content = content;
- getChildren().add(content);
+ getChildren().add(content);
- Scale scale = new Scale(1.0, 1.0);
- content.getTransforms().add(scale);
+ Scale scale = new Scale(1.0, 1.0);
+ content.getTransforms().add(scale);
- resizeFActor.addListener((ObservableValue extends Number> observable, Number oldValue, Number newValue) -> {
- scale.setX(newValue.doubleValue());
- scale.setY(newValue.doubleValue());
- requestLayout();
+ resizeFActor.addListener(
+ (ObservableValue extends Number> observable, Number oldValue, Number newValue) -> {
+ scale.setX(newValue.doubleValue());
+ scale.setY(newValue.doubleValue());
+ requestLayout();
});
- }
-
+ }
- @Override
- protected void layoutChildren() {
- Pos pos = Pos.TOP_LEFT;
- double width = getWidth();
- double height = getHeight();
- double top = getInsets().getTop();
- double right = getInsets().getRight();
- double left = getInsets().getLeft();
- double bottom = getInsets().getBottom();
- double contentWidth = (width - left - right) / resizeFActor.get();
- double contentHeight = (height - top - bottom) / resizeFActor.get();
- layoutInArea(content, left, top,
- contentWidth, contentHeight,
- 0, null,
- pos.getHpos(),
- pos.getVpos());
- }
+ @Override
+ protected void layoutChildren() {
+ Pos pos = Pos.TOP_LEFT;
+ double width = getWidth();
+ double height = getHeight();
+ double top = getInsets().getTop();
+ double right = getInsets().getRight();
+ double left = getInsets().getLeft();
+ double bottom = getInsets().getBottom();
+ double contentWidth = (width - left - right) / resizeFActor.get();
+ double contentHeight = (height - top - bottom) / resizeFActor.get();
+ layoutInArea(
+ content, left, top, contentWidth, contentHeight, 0, null, pos.getHpos(), pos.getVpos());
+ }
- public final Double getResizeFactor() {
- return resizeFActor.get();
- }
+ public final Double getResizeFactor() {
+ return resizeFActor.get();
+ }
- public final void setResizeFactor(Double resizeFactor) {
- this.resizeFActor.set(resizeFactor);
- }
+ public final void setResizeFactor(Double resizeFactor) {
+ this.resizeFActor.set(resizeFactor);
+ }
- public final DoubleProperty resizeFactorProperty() {
- return resizeFActor;
- }
+ public final DoubleProperty resizeFactorProperty() {
+ return resizeFActor;
+ }
}
diff --git a/src/graphvisualizer/containers/ContentZoomPane.java b/src/graphvisualizer/containers/ContentZoomPane.java
index 16842a4..80c6bb8 100644
--- a/src/graphvisualizer/containers/ContentZoomPane.java
+++ b/src/graphvisualizer/containers/ContentZoomPane.java
@@ -36,169 +36,164 @@
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
-import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
/**
* This class provides zooming and panning for a JavaFX node.
*
- * It shows the zoom level with a slider control and reacts to mouse scrolls and
- * mouse dragging.
+ *
It shows the zoom level with a slider control and reacts to mouse scrolls and mouse dragging.
*
- * The content node is out forward in the z-index so it can react to mouse
- * events first. The node should consume any event not meant to propagate to
- * this pane.
+ *
The content node is out forward in the z-index so it can react to mouse events first. The node
+ * should consume any event not meant to propagate to this pane.
*
* @author brunomnsilva
*/
public class ContentZoomPane extends BorderPane {
- /*
- PAN AND ZOOM
- */
- private final DoubleProperty scaleFactorProperty = new ReadOnlyDoubleWrapper(1);
- private final Node content;
+ /*
+ PAN AND ZOOM
+ */
+ private final DoubleProperty scaleFactorProperty = new ReadOnlyDoubleWrapper(1);
+ private final Node content;
- private static final double MIN_SCALE = 1;
- private static final double MAX_SCALE = 5;
- private static final double SCROLL_DELTA = 0.25;
+ private static final double MIN_SCALE = 1;
+ private static final double MAX_SCALE = 5;
+ private static final double SCROLL_DELTA = 0.25;
- public ContentZoomPane(Node content) {
- if (content == null) {
- throw new IllegalArgumentException("Content cannot be null.");
- }
-
- this.content = content;
+ public ContentZoomPane(Node content) {
+ if (content == null) {
+ throw new IllegalArgumentException("Content cannot be null.");
+ }
- Node center = content;
- content.toFront();
+ this.content = content;
- setCenter(center);
- setTop(createSlider());
+ Node center = content;
+ content.toFront();
- enablePanAndZoom();
- }
+ setCenter(center);
+ setTop(createSlider());
- private Node createSlider() {
+ enablePanAndZoom();
+ }
- Slider slider = new Slider(MIN_SCALE, MAX_SCALE, MIN_SCALE);
- slider.setOrientation(Orientation.HORIZONTAL);
- slider.setShowTickMarks(true);
- slider.setShowTickLabels(true);
- slider.setMajorTickUnit(SCROLL_DELTA);
- slider.setMinorTickCount(1);
- slider.setBlockIncrement(0.125f);
- slider.setSnapToTicks(true);
+ private Node createSlider() {
- Text label = new Text("Zoom");
+ Slider slider = new Slider(MIN_SCALE, MAX_SCALE, MIN_SCALE);
+ slider.setOrientation(Orientation.HORIZONTAL);
+ slider.setShowTickMarks(true);
+ slider.setShowTickLabels(true);
+ slider.setMajorTickUnit(SCROLL_DELTA);
+ slider.setMinorTickCount(1);
+ slider.setBlockIncrement(0.125f);
+ slider.setSnapToTicks(true);
- HBox paneSlider = new HBox(label, slider);
+ Text label = new Text("Zoom");
- paneSlider.setPadding(new Insets(10, 10, 10, 10));
- paneSlider.setSpacing(20);
- HBox.setHgrow(slider, Priority.ALWAYS);
+ HBox paneSlider = new HBox(label, slider);
- slider.valueProperty().bind(this.scaleFactorProperty());
-
- return paneSlider;
- }
+ paneSlider.setPadding(new Insets(10, 10, 10, 10));
+ paneSlider.setSpacing(20);
+ HBox.setHgrow(slider, Priority.ALWAYS);
- public void setContentPivot(double x, double y) {
- content.setTranslateX(content.getTranslateX() - x);
- content.setTranslateY(content.getTranslateY() - y);
- }
+ slider.valueProperty().bind(this.scaleFactorProperty());
- public static double boundValue(double value, double min, double max) {
+ return paneSlider;
+ }
- if (Double.compare(value, min) < 0) {
- return min;
- }
+ public void setContentPivot(double x, double y) {
+ content.setTranslateX(content.getTranslateX() - x);
+ content.setTranslateY(content.getTranslateY() - y);
+ }
- if (Double.compare(value, max) > 0) {
- return max;
- }
+ public static double boundValue(double value, double min, double max) {
- return value;
+ if (Double.compare(value, min) < 0) {
+ return min;
}
- private void enablePanAndZoom() {
+ if (Double.compare(value, max) > 0) {
+ return max;
+ }
- setOnScroll((ScrollEvent event) -> {
+ return value;
+ }
- double direction = event.getDeltaY() >= 0 ? 1 : -1;
+ private void enablePanAndZoom() {
- double currentScale = scaleFactorProperty.getValue();
- double computedScale = currentScale + direction * SCROLL_DELTA;
+ setOnScroll(
+ (ScrollEvent event) -> {
+ double direction = event.getDeltaY() >= 0 ? 1 : -1;
- computedScale = boundValue(computedScale, MIN_SCALE, MAX_SCALE);
+ double currentScale = scaleFactorProperty.getValue();
+ double computedScale = currentScale + direction * SCROLL_DELTA;
- if (currentScale != computedScale) {
+ computedScale = boundValue(computedScale, MIN_SCALE, MAX_SCALE);
- content.setScaleX(computedScale);
- content.setScaleY(computedScale);
+ if (currentScale != computedScale) {
- if (computedScale == 1) {
- content.setTranslateX(-getTranslateX());
- content.setTranslateY(-getTranslateY());
- } else {
- scaleFactorProperty.setValue(computedScale);
+ content.setScaleX(computedScale);
+ content.setScaleY(computedScale);
- Bounds bounds = content.localToScene(content.getBoundsInLocal());
- double f = (computedScale / currentScale) - 1;
- double dx = (event.getX() - (bounds.getWidth() / 2 + bounds.getMinX()));
- double dy = (event.getY() - (bounds.getHeight() / 2 + bounds.getMinY()));
+ if (computedScale == 1) {
+ content.setTranslateX(-getTranslateX());
+ content.setTranslateY(-getTranslateY());
+ } else {
+ scaleFactorProperty.setValue(computedScale);
- setContentPivot(f * dx, f * dy);
- }
+ Bounds bounds = content.localToScene(content.getBoundsInLocal());
+ double f = (computedScale / currentScale) - 1;
+ double dx = (event.getX() - (bounds.getWidth() / 2 + bounds.getMinX()));
+ double dy = (event.getY() - (bounds.getHeight() / 2 + bounds.getMinY()));
+ setContentPivot(f * dx, f * dy);
}
- //do not propagate
- event.consume();
-
+ }
+ // do not propagate
+ event.consume();
});
- final DragContext sceneDragContext = new DragContext();
+ final DragContext sceneDragContext = new DragContext();
- setOnMousePressed((MouseEvent event) -> {
+ setOnMousePressed(
+ (MouseEvent event) -> {
+ if (event.isSecondaryButtonDown()) {
+ getScene().setCursor(Cursor.MOVE);
- if (event.isSecondaryButtonDown()) {
- getScene().setCursor(Cursor.MOVE);
-
- sceneDragContext.mouseAnchorX = event.getX();
- sceneDragContext.mouseAnchorY = event.getY();
-
- sceneDragContext.translateAnchorX = content.getTranslateX();
- sceneDragContext.translateAnchorY = content.getTranslateY();
- }
+ sceneDragContext.mouseAnchorX = event.getX();
+ sceneDragContext.mouseAnchorY = event.getY();
+ sceneDragContext.translateAnchorX = content.getTranslateX();
+ sceneDragContext.translateAnchorY = content.getTranslateY();
+ }
});
- setOnMouseReleased((MouseEvent event) -> {
- getScene().setCursor(Cursor.DEFAULT);
+ setOnMouseReleased(
+ (MouseEvent event) -> {
+ getScene().setCursor(Cursor.DEFAULT);
});
- setOnMouseDragged((MouseEvent event) -> {
- if (event.isSecondaryButtonDown()) {
-
- content.setTranslateX(sceneDragContext.translateAnchorX + event.getX() - sceneDragContext.mouseAnchorX);
- content.setTranslateY(sceneDragContext.translateAnchorY + event.getY() - sceneDragContext.mouseAnchorY);
- }
- });
-
- }
+ setOnMouseDragged(
+ (MouseEvent event) -> {
+ if (event.isSecondaryButtonDown()) {
- public DoubleProperty scaleFactorProperty() {
- return scaleFactorProperty;
- }
-
- class DragContext {
+ content.setTranslateX(
+ sceneDragContext.translateAnchorX + event.getX() - sceneDragContext.mouseAnchorX);
+ content.setTranslateY(
+ sceneDragContext.translateAnchorY + event.getY() - sceneDragContext.mouseAnchorY);
+ }
+ });
+ }
- double mouseAnchorX;
- double mouseAnchorY;
+ public DoubleProperty scaleFactorProperty() {
+ return scaleFactorProperty;
+ }
- double translateAnchorX;
- double translateAnchorY;
+ class DragContext {
- }
+ double mouseAnchorX;
+ double mouseAnchorY;
+ double translateAnchorX;
+ double translateAnchorY;
+ }
}
diff --git a/src/graphvisualizer/containers/MenuPane.java b/src/graphvisualizer/containers/MenuPane.java
index 8d7f43b..e8cf5cd 100644
--- a/src/graphvisualizer/containers/MenuPane.java
+++ b/src/graphvisualizer/containers/MenuPane.java
@@ -1,6 +1,10 @@
package graphvisualizer.containers;
import graphvisualizer.graphview.SmartGraphPanel;
+import java.io.File;
+import java.net.MalformedURLException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
@@ -8,89 +12,85 @@
import javafx.scene.control.TextArea;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
-import java.io.File;
-import java.net.MalformedURLException;
-import java.util.logging.Level;
-import java.util.logging.Logger;
public class MenuPane extends VBox {
- private Button strongConnectivityButton;
- private Button cycleDetectionButton;
- private Button shortestPathButton;
- private Button resetButton;
- private Button addVertexButton;
- private TextArea statusBox;
-
- public MenuPane() {
- setSpacing(40);
- setAlignment(Pos.TOP_CENTER);
- createButton();
- createStatusBox();
- loadStylesheet();
- }
-
- private void loadStylesheet() {
- try {
- getStylesheets().add(new File("menu.css").toURI().toURL().toExternalForm());
- this.getStyleClass().add("menu");
- } catch (MalformedURLException ex) {
- Logger.getLogger(SmartGraphPanel.class.getName()).log(Level.SEVERE, null, ex);
- }
- }
-
- private void createButton() {
- strongConnectivityButton = new Button("STRONG CONNECTIVITY");
- strongConnectivityButton.getStyleClass().add("function-button");
- getChildren().add(strongConnectivityButton);
-
- cycleDetectionButton = new Button("CYCLE DETECTION");
- cycleDetectionButton.getStyleClass().add("function-button");
- getChildren().add(cycleDetectionButton);
-
- shortestPathButton = new Button("SHORTEST PATH");
- shortestPathButton.getStyleClass().add("function-button");
- getChildren().add(shortestPathButton);
-
- addVertexButton = new Button("ADD VERTEX");
- addVertexButton.getStyleClass().add("add-vertex-button");
- getChildren().add(addVertexButton);
-
- resetButton = new Button("RESET");
- resetButton.getStyleClass().add("reset-button");
- getChildren().add(resetButton);
- }
-
- private void createStatusBox() {
- statusBox = new TextArea();
- statusBox.setWrapText(true);
- statusBox.setEditable(false);
- statusBox.setFocusTraversable(false);
- statusBox.getStyleClass().add("status-box");
- getChildren().add(statusBox);
- setVgrow(statusBox, Priority.ALWAYS);
- }
-
- public TextArea getStatusBox() {
- return statusBox;
- }
-
- public void setStrongConnectivityButtonAction(EventHandler actionEvent) {
- strongConnectivityButton.setOnAction(actionEvent);
- }
-
- public void setCycleDetectionButtonAction(EventHandler actionEvent) {
- cycleDetectionButton.setOnAction(actionEvent);
- }
-
- public void setShortestPathButtonAction(EventHandler actionEvent) {
- shortestPathButton.setOnAction(actionEvent);
- }
-
- public void setResetButtonAction(EventHandler actionEvent) {
- resetButton.setOnAction(actionEvent);
- }
-
- public void setAddVertexButtonAction(EventHandler actionEvent) {
- addVertexButton.setOnAction(actionEvent);
+ private Button strongConnectivityButton;
+ private Button cycleDetectionButton;
+ private Button shortestPathButton;
+ private Button resetButton;
+ private Button addVertexButton;
+ private TextArea statusBox;
+
+ public MenuPane() {
+ setSpacing(40);
+ setAlignment(Pos.TOP_CENTER);
+ createButton();
+ createStatusBox();
+ loadStylesheet();
+ }
+
+ private void loadStylesheet() {
+ try {
+ getStylesheets().add(new File("menu.css").toURI().toURL().toExternalForm());
+ this.getStyleClass().add("menu");
+ } catch (MalformedURLException ex) {
+ Logger.getLogger(SmartGraphPanel.class.getName()).log(Level.SEVERE, null, ex);
}
+ }
+
+ private void createButton() {
+ strongConnectivityButton = new Button("STRONG CONNECTIVITY");
+ strongConnectivityButton.getStyleClass().add("function-button");
+ getChildren().add(strongConnectivityButton);
+
+ cycleDetectionButton = new Button("CYCLE DETECTION");
+ cycleDetectionButton.getStyleClass().add("function-button");
+ getChildren().add(cycleDetectionButton);
+
+ shortestPathButton = new Button("SHORTEST PATH");
+ shortestPathButton.getStyleClass().add("function-button");
+ getChildren().add(shortestPathButton);
+
+ addVertexButton = new Button("ADD VERTEX");
+ addVertexButton.getStyleClass().add("add-vertex-button");
+ getChildren().add(addVertexButton);
+
+ resetButton = new Button("RESET");
+ resetButton.getStyleClass().add("reset-button");
+ getChildren().add(resetButton);
+ }
+
+ private void createStatusBox() {
+ statusBox = new TextArea();
+ statusBox.setWrapText(true);
+ statusBox.setEditable(false);
+ statusBox.setFocusTraversable(false);
+ statusBox.getStyleClass().add("status-box");
+ getChildren().add(statusBox);
+ setVgrow(statusBox, Priority.ALWAYS);
+ }
+
+ public TextArea getStatusBox() {
+ return statusBox;
+ }
+
+ public void setStrongConnectivityButtonAction(EventHandler actionEvent) {
+ strongConnectivityButton.setOnAction(actionEvent);
+ }
+
+ public void setCycleDetectionButtonAction(EventHandler actionEvent) {
+ cycleDetectionButton.setOnAction(actionEvent);
+ }
+
+ public void setShortestPathButtonAction(EventHandler actionEvent) {
+ shortestPathButton.setOnAction(actionEvent);
+ }
+
+ public void setResetButtonAction(EventHandler actionEvent) {
+ resetButton.setOnAction(actionEvent);
+ }
+
+ public void setAddVertexButtonAction(EventHandler actionEvent) {
+ addVertexButton.setOnAction(actionEvent);
+ }
}
diff --git a/src/graphvisualizer/containers/SmartGraphDemoContainer.java b/src/graphvisualizer/containers/SmartGraphDemoContainer.java
index 008eec1..c308ab4 100644
--- a/src/graphvisualizer/containers/SmartGraphDemoContainer.java
+++ b/src/graphvisualizer/containers/SmartGraphDemoContainer.java
@@ -23,26 +23,22 @@
*/
package graphvisualizer.containers;
-import javafx.scene.control.CheckBox;
-import javafx.scene.control.Menu;
-import javafx.scene.layout.BorderPane;
-import javafx.scene.layout.HBox;
import graphvisualizer.graphview.SmartGraphPanel;
+import javafx.scene.layout.BorderPane;
/**
- *
* @author Bruno Silva
*/
public class SmartGraphDemoContainer extends BorderPane {
- private MenuPane menu;
+ private MenuPane menu;
- public SmartGraphDemoContainer(SmartGraphPanel graphView) {
- setCenter(new ContentResizerPane(graphView));
- menu = new MenuPane();
- setRight(menu);
- }
+ public SmartGraphDemoContainer(SmartGraphPanel graphView) {
+ setCenter(new ContentResizerPane(graphView));
+ menu = new MenuPane();
+ setRight(menu);
+ }
- public MenuPane getMenu() {
- return menu;
- }
+ public MenuPane getMenu() {
+ return menu;
+ }
}
diff --git a/src/graphvisualizer/graph/AbstractPriorityQueue.java b/src/graphvisualizer/graph/AbstractPriorityQueue.java
index 8310edd..ebd835f 100644
--- a/src/graphvisualizer/graph/AbstractPriorityQueue.java
+++ b/src/graphvisualizer/graph/AbstractPriorityQueue.java
@@ -2,50 +2,71 @@
import java.util.Comparator;
-//An abstract base class to assist implementations of the PriorityQueue interface
-public abstract class AbstractPriorityQueue implements PriorityQueue{
-
- //start of nested PQEntry class
- protected static class PQEntry implements Entry {
- private K k;
- private V v;
- public PQEntry(K key, V value){
- k = key;
- v = value;
- }
- //methods of the Entry interface
- public K getKey() {return k;}
- public V getValue() {return v;}
- //utilities not exposed as part of the Entry interface
- protected void setKey(K key) {k=key;}
- protected void setValue(V value) {v=value;}
+// An abstract base class to assist implementations of the PriorityQueue interface
+public abstract class AbstractPriorityQueue implements PriorityQueue {
+
+ // start of nested PQEntry class
+ protected static class PQEntry implements Entry {
+ private K k;
+ private V v;
+
+ public PQEntry(K key, V value) {
+ k = key;
+ v = value;
+ }
+
+ // methods of the Entry interface
+ public K getKey() {
+ return k;
}
- //end of nested PQEntry class
-
- //instance variable for an AbstractPriorityQueue
-
- //The comparator defining the ordering of keys in the priority queue
- protected Comparator comp;
- //Creates an empty priority queue using the given comparator to order keys
- protected AbstractPriorityQueue(Comparator c) {comp=c;}
- //Creates an empty priority queue based on the natural ordering of its keys
- protected AbstractPriorityQueue() {this(new DefaultComparator());}
- //Method for comparing two entries according to key
- protected int compare(Entry a, Entry b){
- return comp.compare(a.getKey(),b.getKey());
+
+ public V getValue() {
+ return v;
+ }
+
+ // utilities not exposed as part of the Entry interface
+ protected void setKey(K key) {
+ k = key;
}
- //Determines whether a key is valid
- protected boolean checkKey(K key) throws IllegalArgumentException {
- try{
- return(comp.compare(key,key)==0); //see if key can be compared to itself
- } catch (ClassCastException e) {
- throw new IllegalArgumentException("Incompatible key");
- }
+ protected void setValue(V value) {
+ v = value;
}
+ }
- //Tests whether the priority queue is empty
- public boolean isEmpty() {
- return size()==0;
+ // end of nested PQEntry class
+
+ // instance variable for an AbstractPriorityQueue
+
+ // The comparator defining the ordering of keys in the priority queue
+ protected Comparator comp;
+
+ // Creates an empty priority queue using the given comparator to order keys
+ protected AbstractPriorityQueue(Comparator c) {
+ comp = c;
+ }
+
+ // Creates an empty priority queue based on the natural ordering of its keys
+ protected AbstractPriorityQueue() {
+ this(new DefaultComparator());
+ }
+
+ // Method for comparing two entries according to key
+ protected int compare(Entry a, Entry b) {
+ return comp.compare(a.getKey(), b.getKey());
+ }
+
+ // Determines whether a key is valid
+ protected boolean checkKey(K key) throws IllegalArgumentException {
+ try {
+ return (comp.compare(key, key) == 0); // see if key can be compared to itself
+ } catch (ClassCastException e) {
+ throw new IllegalArgumentException("Incompatible key");
}
-}
\ No newline at end of file
+ }
+
+ // Tests whether the priority queue is empty
+ public boolean isEmpty() {
+ return size() == 0;
+ }
+}
diff --git a/src/graphvisualizer/graph/AdaptablePriorityQueue.java b/src/graphvisualizer/graph/AdaptablePriorityQueue.java
index bbf2d58..f2f4400 100644
--- a/src/graphvisualizer/graph/AdaptablePriorityQueue.java
+++ b/src/graphvisualizer/graph/AdaptablePriorityQueue.java
@@ -1,7 +1,8 @@
package graphvisualizer.graph;
-//Interface for AdaptablePriorityQueue
+// Interface for AdaptablePriorityQueue
public interface AdaptablePriorityQueue {
- void remove (Entry entry); //Removes the given entry from the priority queue
- void replaceKey (Entry entry, K key); //Replaces the key of an entry
-}
\ No newline at end of file
+ void remove(Entry entry); // Removes the given entry from the priority queue
+
+ void replaceKey(Entry entry, K key); // Replaces the key of an entry
+}
diff --git a/src/graphvisualizer/graph/AdjacencyMapDigraph.java b/src/graphvisualizer/graph/AdjacencyMapDigraph.java
index a6da97d..dc9d723 100644
--- a/src/graphvisualizer/graph/AdjacencyMapDigraph.java
+++ b/src/graphvisualizer/graph/AdjacencyMapDigraph.java
@@ -3,348 +3,353 @@
import java.util.*;
/**
- * An adjacency map structure for a directed graph. A double map structure is used
- * to represent the directed graph. The vertices are stored in the a map. The outgoing
- * and incoming edges are stored in two maps of the corresponding vertex. The double
- * map structure can be used since the vertices added are unique i.e. with unique
- * String
labels. This structure provides similar performance to an
- * adjacency matrix where the {@link #getEdge(Vertex u, Vertex v)} method can achieve
- * O(1) by performing lookup on the first and second map respectively.
+ * An adjacency map structure for a directed graph. A double map structure is used to represent the
+ * directed graph. The vertices are stored in the a map. The outgoing and incoming edges are stored
+ * in two maps of the corresponding vertex. The double map structure can be used since the vertices
+ * added are unique i.e. with unique String
labels. This structure provides similar
+ * performance to an adjacency matrix where the {@link #getEdge(Vertex u, Vertex v)} method can
+ * achieve O(1) by performing lookup on the first and second map respectively.
*
* @param Vertex type
* @param Edge type
*/
public class AdjacencyMapDigraph implements Graph {
- /**
- * Concrete implementation of {@link Vertex}. A {@link DVertex} object stores
- * a {@link V} element and its edges. Edges are implemented as {@link LinkedHashMap}
- * to provide O(1) lookup and also maintain the insertion order.
- */
- private class DVertex implements Vertex {
- private V element;
- private Map, Edge> outgoingEdges, incomingEdges;
-
- public DVertex(V element) {
- this.element = element;
- outgoingEdges = new LinkedHashMap<>();
- incomingEdges = new LinkedHashMap<>();
- }
-
- @Override
- public V element() {
- return element;
- }
-
- public Map, Edge> getOutgoingEdges() {
- return outgoingEdges;
- }
-
- public Map, Edge> getIncomingEdges() {
- return incomingEdges;
- }
-
- @Override
- public String toString() {
- return "Vertex{" + element + "}";
- }
-
- /*
- 2 DVertex objects are equals if their elements are equal.
- Override hashCode() if override equals()
- */
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- DVertex vertex = (DVertex) o;
- return element.equals(vertex.element);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(element);
- }
- }
-
- /**
- * Concrete implementation of {@link Edge}. A {@link DEdge} object stores
- * an {@link E} element and its {@link V} end vertices.
- */
- private class DEdge implements Edge {
- private E element;
- private Vertex[] endVertices;
-
- public DEdge(Vertex u, Vertex v, E element) {
- this.element = element;
- this.endVertices = (Vertex[]) new Vertex[]{u, v};
- }
-
- @Override
- public E element() {
- return element;
- }
-
- @Override
- public Vertex[] vertices() {
- return endVertices;
- }
-
- @Override
- public String toString() {
- return "Edge from " + endVertices[0] + " to " + endVertices[1] + " with weight of " + element;
- }
-
- /*
- 2 DEdge objects are equals if their end vertices elements are equal.
- Override hashCode() if override equals()
- */
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- DEdge edge = (DEdge) o;
- return Arrays.equals(endVertices, edge.endVertices);
- }
-
- @Override
- public int hashCode() {
- return Arrays.hashCode(endVertices);
- }
+ /**
+ * Concrete implementation of {@link Vertex}. A {@link DVertex} object stores a {@link V} element
+ * and its edges. Edges are implemented as {@link LinkedHashMap} to provide O(1) lookup and also
+ * maintain the insertion order.
+ */
+ private class DVertex implements Vertex {
+ private V element;
+ private Map, Edge> outgoingEdges, incomingEdges;
+
+ public DVertex(V element) {
+ this.element = element;
+ outgoingEdges = new LinkedHashMap<>();
+ incomingEdges = new LinkedHashMap<>();
}
- private Map> vertices;
- private Set> edges;
-
- /*
- LinkedHashMap is used to provide a map interface and maintain the insertion order of
- vertices and elements. This also provides a faster iteration in the Java for-each loop
- than HashMap.
- */
- public AdjacencyMapDigraph() {
- this.vertices = new LinkedHashMap<>();
- this.edges = new LinkedHashSet<>();
+ @Override
+ public V element() {
+ return element;
}
- public synchronized void clear() {
- vertices.clear();
- edges.clear();
+ public Map, Edge> getOutgoingEdges() {
+ return outgoingEdges;
}
- @Override
- public int numVertices() {
- return vertices.size();
+ public Map, Edge> getIncomingEdges() {
+ return incomingEdges;
}
@Override
- public int numEdges() {
- return edges.size();
+ public String toString() {
+ return "Vertex{" + element + "}";
}
/*
- synchronized methods are used to prevent thread interference since the graph visualization is
- run using a non-javafx thread according to the author of JavaFX SmartGraph library.
+ 2 DVertex objects are equals if their elements are equal.
+ Override hashCode() if override equals()
*/
@Override
- public synchronized Collection> vertices() {
- return vertices.values();
- }
-
- @Override
- public synchronized Collection> edges() {
- return edges;
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ DVertex vertex = (DVertex) o;
+ return element.equals(vertex.element);
}
@Override
- public synchronized Collection> incomingEdges(Vertex v) throws InvalidVertexException {
- DVertex vertex = validateVertex(v);
- return vertex.getIncomingEdges().values();
+ public int hashCode() {
+ return Objects.hash(element);
}
-
- @Override
- public synchronized Collection> outgoingEdges(Vertex v) throws InvalidVertexException {
- DVertex vertex = validateVertex(v);
- return vertex.getOutgoingEdges().values();
+ }
+
+ /**
+ * Concrete implementation of {@link Edge}. A {@link DEdge} object stores an {@link E} element and
+ * its {@link V} end vertices.
+ */
+ private class DEdge implements Edge {
+ private E element;
+ private Vertex[] endVertices;
+
+ public DEdge(Vertex u, Vertex v, E element) {
+ this.element = element;
+ this.endVertices = (Vertex[]) new Vertex[] {u, v};
}
@Override
- public synchronized Vertex opposite(Vertex v, Edge e) throws InvalidVertexException, InvalidEdgeException {
- DVertex vertex = validateVertex(v);
- DEdge edge = validateEdge(e);
- Vertex[] endVertices = edge.vertices();
-
- if(endVertices[0].equals(vertex)) {
- return endVertices[1];
- }
- else if (endVertices[1].equals(vertex)) {
- return endVertices[0];
- }
- else {
- throw new InvalidEdgeException("v is not incident to this edge.");
- }
+ public E element() {
+ return element;
}
@Override
- public synchronized Vertex insertVertex(V element) throws InvalidVertexException {
- if (vertices.containsKey(element)) {
- throw new InvalidVertexException("A vertex with this element already exists.");
- }
- else {
- DVertex vertex = new DVertex(element);
- vertices.put(element, vertex);
- return vertex;
- }
+ public Vertex[] vertices() {
+ return endVertices;
}
@Override
- public synchronized Edge getEdge(Vertex u, Vertex v) throws InvalidVertexException {
- DVertex startVertex = validateVertex(u);
- return startVertex.getOutgoingEdges().get(v);
+ public String toString() {
+ return "Edge from " + endVertices[0] + " to " + endVertices[1] + " with weight of " + element;
}
+ /*
+ 2 DEdge objects are equals if their end vertices elements are equal.
+ Override hashCode() if override equals()
+ */
@Override
- public synchronized Edge insertEdge(Vertex u, Vertex v, E element) throws InvalidVertexException, InvalidEdgeException {
- if(getEdge(u, v) == null) {
- DVertex startVertex = validateVertex(u);
- DVertex endVertex = validateVertex(v);
- DEdge edge = new DEdge(startVertex, endVertex, element);
- edges.add(edge);
- startVertex.getOutgoingEdges().put(endVertex, edge);
- endVertex.getIncomingEdges().put(startVertex, edge);
- return edge;
- }
- else {
- throw new InvalidEdgeException("Edge from u to v exists.");
- }
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ DEdge edge = (DEdge) o;
+ return Arrays.equals(endVertices, edge.endVertices);
}
@Override
- public synchronized Edge insertEdge(V uElement, V vElement, E eElement) throws InvalidVertexException, InvalidEdgeException {
- DVertex startVertex = validateVertex(vertices.get(uElement));
- DVertex endVertex = validateVertex(vertices.get(vElement));
-
- if(getEdge(startVertex, endVertex) == null) {
- DEdge edge = new DEdge(startVertex, endVertex, eElement);
- edges.add(edge);
- startVertex.getOutgoingEdges().put(endVertex, edge);
- endVertex.getIncomingEdges().put(startVertex, edge);
- return edge;
- }
- else {
- throw new InvalidEdgeException("Edge from u to v exists.");
- }
+ public int hashCode() {
+ return Arrays.hashCode(endVertices);
}
+ }
+
+ private Map> vertices;
+ private Set> edges;
+
+ /*
+ LinkedHashMap is used to provide a map interface and maintain the insertion order of
+ vertices and elements. This also provides a faster iteration in the Java for-each loop
+ than HashMap.
+ */
+ public AdjacencyMapDigraph() {
+ this.vertices = new LinkedHashMap<>();
+ this.edges = new LinkedHashSet<>();
+ }
+
+ public synchronized void clear() {
+ vertices.clear();
+ edges.clear();
+ }
+
+ @Override
+ public int numVertices() {
+ return vertices.size();
+ }
+
+ @Override
+ public int numEdges() {
+ return edges.size();
+ }
+
+ /*
+ synchronized methods are used to prevent thread interference since the graph visualization is
+ run using a non-javafx thread according to the author of JavaFX SmartGraph library.
+ */
+ @Override
+ public synchronized Collection> vertices() {
+ return vertices.values();
+ }
+
+ @Override
+ public synchronized Collection> edges() {
+ return edges;
+ }
+
+ @Override
+ public synchronized Collection> incomingEdges(Vertex v)
+ throws InvalidVertexException {
+ DVertex vertex = validateVertex(v);
+ return vertex.getIncomingEdges().values();
+ }
+
+ @Override
+ public synchronized Collection> outgoingEdges(Vertex v)
+ throws InvalidVertexException {
+ DVertex vertex = validateVertex(v);
+ return vertex.getOutgoingEdges().values();
+ }
+
+ @Override
+ public synchronized Vertex opposite(Vertex v, Edge e)
+ throws InvalidVertexException, InvalidEdgeException {
+ DVertex vertex = validateVertex(v);
+ DEdge edge = validateEdge(e);
+ Vertex[] endVertices = edge.vertices();
+
+ if (endVertices[0].equals(vertex)) {
+ return endVertices[1];
+ } else if (endVertices[1].equals(vertex)) {
+ return endVertices[0];
+ } else {
+ throw new InvalidEdgeException("v is not incident to this edge.");
+ }
+ }
+
+ @Override
+ public synchronized Vertex insertVertex(V element) throws InvalidVertexException {
+ if (vertices.containsKey(element)) {
+ throw new InvalidVertexException("A vertex with this element already exists.");
+ } else {
+ DVertex vertex = new DVertex(element);
+ vertices.put(element, vertex);
+ return vertex;
+ }
+ }
+
+ @Override
+ public synchronized Edge getEdge(Vertex u, Vertex v) throws InvalidVertexException {
+ DVertex startVertex = validateVertex(u);
+ return startVertex.getOutgoingEdges().get(v);
+ }
+
+ @Override
+ public synchronized Edge insertEdge(Vertex u, Vertex v, E element)
+ throws InvalidVertexException, InvalidEdgeException {
+ if (getEdge(u, v) == null) {
+ DVertex startVertex = validateVertex(u);
+ DVertex endVertex = validateVertex(v);
+ DEdge edge = new DEdge(startVertex, endVertex, element);
+ edges.add(edge);
+ startVertex.getOutgoingEdges().put(endVertex, edge);
+ endVertex.getIncomingEdges().put(startVertex, edge);
+ return edge;
+ } else {
+ throw new InvalidEdgeException("Edge from u to v exists.");
+ }
+ }
+
+ @Override
+ public synchronized Edge insertEdge(V uElement, V vElement, E eElement)
+ throws InvalidVertexException, InvalidEdgeException {
+ DVertex startVertex = validateVertex(vertices.get(uElement));
+ DVertex endVertex = validateVertex(vertices.get(vElement));
+
+ if (getEdge(startVertex, endVertex) == null) {
+ DEdge edge = new DEdge(startVertex, endVertex, eElement);
+ edges.add(edge);
+ startVertex.getOutgoingEdges().put(endVertex, edge);
+ endVertex.getIncomingEdges().put(startVertex, edge);
+ return edge;
+ } else {
+ throw new InvalidEdgeException("Edge from u to v exists.");
+ }
+ }
- @Override
- public synchronized V removeVertex(Vertex v) throws InvalidVertexException {
- DVertex vertex = validateVertex(v);
- List> removedEdges = new LinkedList<>();
-
- removedEdges.addAll(vertex.getIncomingEdges().values());
- removedEdges.addAll(vertex.getOutgoingEdges().values());
+ @Override
+ public synchronized V removeVertex(Vertex v) throws InvalidVertexException {
+ DVertex vertex = validateVertex(v);
+ List> removedEdges = new LinkedList<>();
- for (Edge edge : removedEdges) {
- removeEdge(edge);
- }
+ removedEdges.addAll(vertex.getIncomingEdges().values());
+ removedEdges.addAll(vertex.getOutgoingEdges().values());
- V element = v.element();
- vertices.remove(v.element());
- return element;
+ for (Edge edge : removedEdges) {
+ removeEdge(edge);
}
- @Override
- public synchronized E removeEdge(Edge e) throws InvalidEdgeException {
- DEdge edge = validateEdge(e);
- Vertex[] endVertices = edge.vertices();
- DVertex startVertex = validateVertex(endVertices[0]);
- DVertex endVertex = validateVertex(endVertices[1]);
-
- startVertex.getOutgoingEdges().remove(endVertex);
- endVertex.getIncomingEdges().remove(startVertex);
- E element = edge.element();
- edges.remove(edge);
- return element;
+ V element = v.element();
+ vertices.remove(v.element());
+ return element;
+ }
+
+ @Override
+ public synchronized E removeEdge(Edge e) throws InvalidEdgeException {
+ DEdge edge = validateEdge(e);
+ Vertex[] endVertices = edge.vertices();
+ DVertex startVertex = validateVertex(endVertices[0]);
+ DVertex endVertex = validateVertex(endVertices[1]);
+
+ startVertex.getOutgoingEdges().remove(endVertex);
+ endVertex.getIncomingEdges().remove(startVertex);
+ E element = edge.element();
+ edges.remove(edge);
+ return element;
+ }
+
+ public synchronized String generateRandomEdge(E randomElement) {
+ StringBuilder sb = new StringBuilder();
+ if (numEdges()
+ == numVertices() * (numVertices() - 1)) // maximum no. of edges in digraph is n(n - 1)
+ return sb.append("Graph has maximum number of edges.\n").toString();
+
+ Random random;
+ List randomVertices = new ArrayList<>(vertices.keySet());
+ V randomVertex;
+ DVertex startVertex, endVertex;
+
+ for (; ; ) { // continue to generate a new random edge between random vertices if invalid
+ random = new Random();
+ randomVertex = randomVertices.get(random.nextInt(randomVertices.size()));
+ startVertex = validateVertex(vertices.get(randomVertex));
+
+ random = new Random();
+ randomVertex = randomVertices.get(random.nextInt(randomVertices.size()));
+ endVertex = validateVertex(vertices.get(randomVertex));
+
+ if (startVertex.equals(endVertex)) // self-loop is not allowed, retry
+ continue;
+ else if (getEdge(startVertex, endVertex)
+ == null) { // a random edge from u to v does not exist
+ return sb.append(insertEdge(startVertex, endVertex, randomElement))
+ .append(" is generated.\n")
+ .toString();
+ } else if (getEdge(endVertex, startVertex)
+ == null) { // a random edge from v to u does not exist
+ return sb.append(insertEdge(endVertex, startVertex, randomElement))
+ .append(" is generated.\n")
+ .toString();
+ } // random edges exist between u and v, retry
}
+ }
- public synchronized String generateRandomEdge(E randomElement) {
- StringBuilder sb = new StringBuilder();
- if(numEdges() == numVertices()*(numVertices() - 1)) //maximum no. of edges in digraph is n(n - 1)
- return sb.append("Graph has maximum number of edges.\n").toString();
-
- Random random;
- List randomVertices = new ArrayList<>(vertices.keySet());
- V randomVertex;
- DVertex startVertex, endVertex;
-
- for ( ; ;) { //continue to generate a new random edge between random vertices if invalid
- random = new Random();
- randomVertex = randomVertices.get(random.nextInt(randomVertices.size()));
- startVertex = validateVertex(vertices.get(randomVertex));
-
- random = new Random();
- randomVertex = randomVertices.get(random.nextInt(randomVertices.size()));
- endVertex = validateVertex(vertices.get(randomVertex));
-
- if (startVertex.equals(endVertex)) //self-loop is not allowed, retry
- continue;
- else if (getEdge(startVertex, endVertex) == null) { //a random edge from u to v does not exist
- return sb.append(insertEdge(startVertex, endVertex, randomElement)).append(" is generated.\n").toString();
- }
- else if (getEdge(endVertex, startVertex) == null) { //a random edge from v to u does not exist
- return sb.append(insertEdge(endVertex, startVertex, randomElement)).append(" is generated.\n").toString();
- } //random edges exist between u and v, retry
- }
+ /* validate that this vertex belongs to the graph */
+ private DVertex validateVertex(Vertex v) throws InvalidVertexException {
+ if (v == null) throw new InvalidVertexException("Null vertex.");
+
+ DVertex vertex;
+
+ try {
+ vertex = (DVertex) v;
+ } catch (ClassCastException e) {
+ throw new InvalidVertexException("Not a vertex.");
}
- /* validate that this vertex belongs to the graph */
- private DVertex validateVertex(Vertex v) throws InvalidVertexException {
- if(v == null) throw new InvalidVertexException("Null vertex.");
-
- DVertex vertex;
-
- try {
- vertex = (DVertex) v;
- } catch (ClassCastException e) {
- throw new InvalidVertexException("Not a vertex.");
- }
-
- if (!vertices.containsKey(vertex.element)) {
- throw new InvalidVertexException("Vertex does not belong to this graph.");
- }
- return vertex;
+ if (!vertices.containsKey(vertex.element)) {
+ throw new InvalidVertexException("Vertex does not belong to this graph.");
}
+ return vertex;
+ }
+
+ /* validate that this edge belongs to the graph */
+ private DEdge validateEdge(Edge e) throws InvalidEdgeException {
+ if (e == null) throw new InvalidEdgeException("Null edge.");
+
+ DEdge edge;
- /* validate that this edge belongs to the graph */
- private DEdge validateEdge(Edge e) throws InvalidEdgeException {
- if(e == null) throw new InvalidEdgeException("Null edge.");
-
- DEdge edge;
-
- try {
- edge = (DEdge) e;
- } catch (ClassCastException ex) {
- throw new InvalidVertexException("Not an adge.");
- }
-
- if (!edges.contains(edge)) {
- throw new InvalidEdgeException("Edge does not belong to this graph.");
- }
- return edge;
+ try {
+ edge = (DEdge) e;
+ } catch (ClassCastException ex) {
+ throw new InvalidVertexException("Not an adge.");
}
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder(
- String.format("[Graph with %d vertices and %d edges]\n", numVertices(), numEdges())
- );
-
- sb.append("--- Vertices: \n");
- for (Vertex v : vertices.values()) {
- sb.append("\t").append(v.toString()).append("\n");
- }
- sb.append("\n--- Edges: \n");
- for (Edge e : edges) {
- sb.append("\t").append(e.toString()).append("\n");
- }
- return sb.append("\n").toString();
+ if (!edges.contains(edge)) {
+ throw new InvalidEdgeException("Edge does not belong to this graph.");
+ }
+ return edge;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb =
+ new StringBuilder(
+ String.format("[Graph with %d vertices and %d edges]\n", numVertices(), numEdges()));
+
+ sb.append("--- Vertices: \n");
+ for (Vertex v : vertices.values()) {
+ sb.append("\t").append(v.toString()).append("\n");
+ }
+ sb.append("\n--- Edges: \n");
+ for (Edge e : edges) {
+ sb.append("\t").append(e.toString()).append("\n");
}
-}
\ No newline at end of file
+ return sb.append("\n").toString();
+ }
+}
diff --git a/src/graphvisualizer/graph/DefaultComparator.java b/src/graphvisualizer/graph/DefaultComparator.java
index 5fc83c7..17bce65 100644
--- a/src/graphvisualizer/graph/DefaultComparator.java
+++ b/src/graphvisualizer/graph/DefaultComparator.java
@@ -3,7 +3,7 @@
import java.util.Comparator;
public class DefaultComparator implements Comparator {
- public int compare(E a, E b) throws ClassCastException {
- return ((Comparable) a).compareTo(b);
- }
+ public int compare(E a, E b) throws ClassCastException {
+ return ((Comparable) a).compareTo(b);
+ }
}
diff --git a/src/graphvisualizer/graph/Edge.java b/src/graphvisualizer/graph/Edge.java
index 5fe90a5..55e49bf 100644
--- a/src/graphvisualizer/graph/Edge.java
+++ b/src/graphvisualizer/graph/Edge.java
@@ -1,8 +1,9 @@
package graphvisualizer.graph;
public interface Edge {
- /* return element stored in edge */
- E element();
- /* return 2 end vertices connected by edge */
- Vertex[] vertices();
+ /* return element stored in edge */
+ E element();
+
+ /* return 2 end vertices connected by edge */
+ Vertex[] vertices();
}
diff --git a/src/graphvisualizer/graph/Entry.java b/src/graphvisualizer/graph/Entry.java
index bf8da96..5c6b3b2 100644
--- a/src/graphvisualizer/graph/Entry.java
+++ b/src/graphvisualizer/graph/Entry.java
@@ -1,8 +1,9 @@
package graphvisualizer.graph;
-//Interface for a key-value pair
-public interface Entry {
+// Interface for a key-value pair
+public interface Entry {
- K getKey(); //return the key stored in this entry
- V getValue(); //return the value stored in this entry
+ K getKey(); // return the key stored in this entry
+
+ V getValue(); // return the value stored in this entry
}
diff --git a/src/graphvisualizer/graph/Graph.java b/src/graphvisualizer/graph/Graph.java
index 4497e63..2943295 100644
--- a/src/graphvisualizer/graph/Graph.java
+++ b/src/graphvisualizer/graph/Graph.java
@@ -3,30 +3,44 @@
import java.util.Collection;
public interface Graph {
- /* return total number of vertices */
- int numVertices();
- /* return total number of edges */
- int numEdges();
- /* return iteration of all vertices */
- Collection> vertices();
- /* return iteration of all edges */
- Collection> edges();
- /* return iteration of all incoming edges */
- Collection> incomingEdges(Vertex v) throws InvalidVertexException;
- /* return iteration of all outgoing edges */
- Collection> outgoingEdges(Vertex v) throws InvalidVertexException;
- /* return opposite vertex */
- Vertex opposite(Vertex v, Edge e) throws InvalidVertexException, InvalidEdgeException;
- /* create and return a new vertex */
- Vertex insertVertex(V element) throws InvalidVertexException;
- /* return a new edge from u to v or null if not exists */
- Edge getEdge(Vertex u, Vertex v) throws InvalidVertexException, InvalidEdgeException;
- /* create and return a new edge using vertex instance */
- Edge insertEdge(Vertex u, Vertex v, E element) throws InvalidVertexException, InvalidEdgeException;
- /* create and return a new edge using vertex element */
- Edge insertEdge(V uElement, V vElement, E eElement) throws InvalidVertexException, InvalidEdgeException;
- /* remove a vertex and all incident edges */
- V removeVertex(Vertex v) throws InvalidVertexException;
- /* remove an edge */
- E removeEdge(Edge e) throws InvalidEdgeException;
-}
\ No newline at end of file
+ /* return total number of vertices */
+ int numVertices();
+
+ /* return total number of edges */
+ int numEdges();
+
+ /* return iteration of all vertices */
+ Collection> vertices();
+
+ /* return iteration of all edges */
+ Collection> edges();
+
+ /* return iteration of all incoming edges */
+ Collection> incomingEdges(Vertex v) throws InvalidVertexException;
+
+ /* return iteration of all outgoing edges */
+ Collection> outgoingEdges(Vertex v) throws InvalidVertexException;
+
+ /* return opposite vertex */
+ Vertex opposite(Vertex v, Edge e) throws InvalidVertexException, InvalidEdgeException;
+
+ /* create and return a new vertex */
+ Vertex insertVertex(V element) throws InvalidVertexException;
+
+ /* return a new edge from u to v or null if not exists */
+ Edge getEdge(Vertex u, Vertex v) throws InvalidVertexException, InvalidEdgeException;
+
+ /* create and return a new edge using vertex instance */
+ Edge insertEdge(Vertex u, Vertex v, E element)
+ throws InvalidVertexException, InvalidEdgeException;
+
+ /* create and return a new edge using vertex element */
+ Edge insertEdge(V uElement, V vElement, E eElement)
+ throws InvalidVertexException, InvalidEdgeException;
+
+ /* remove a vertex and all incident edges */
+ V removeVertex(Vertex v) throws InvalidVertexException;
+
+ /* remove an edge */
+ E removeEdge(Edge e) throws InvalidEdgeException;
+}
diff --git a/src/graphvisualizer/graph/HeapAdaptablePriorityQueue.java b/src/graphvisualizer/graph/HeapAdaptablePriorityQueue.java
index d347f69..4eefd86 100644
--- a/src/graphvisualizer/graph/HeapAdaptablePriorityQueue.java
+++ b/src/graphvisualizer/graph/HeapAdaptablePriorityQueue.java
@@ -2,78 +2,88 @@
import java.util.Comparator;
-//An implementation of an adaptable priority queue using an array-based heap
-public class HeapAdaptablePriorityQueue extends HeapPriorityQueue implements AdaptablePriorityQueue {
+// An implementation of an adaptable priority queue using an array-based heap
+public class HeapAdaptablePriorityQueue extends HeapPriorityQueue
+ implements AdaptablePriorityQueue {
- //nested Adaptable PQEntry class
- protected static class AdaptablePQEntry extends PQEntry{
- private int index;
- public AdaptablePQEntry(K key, V value, int j){
- super(key, value);
- index=j;
- }
- public int getIndex(){return index;}
- public void setIndex(int j) {index=j;}
- } //end of nested Adaptable PQEntry class
+ // nested Adaptable PQEntry class
+ protected static class AdaptablePQEntry extends PQEntry {
+ private int index;
- //Creates an empty adaptable priority queue using natural ordering of keys
- public HeapAdaptablePriorityQueue(){super();}
- //Creates an empty adaptable priority queue using the given comparator
- public HeapAdaptablePriorityQueue(Comparator comp) { super(comp);}
-
- //Validates an entry to ensure it is location-aware
- protected AdaptablePQEntry validate(Entry entry) throws IllegalArgumentException{
- if (!(entry instanceof AdaptablePQEntry))
- throw new IllegalArgumentException("Invalid Entry");
- AdaptablePQEntry locator = (AdaptablePQEntry) entry;
- int j = locator.getIndex();
- if (j>=heap.size()||heap.get(j)!=locator)
- throw new IllegalArgumentException("Invalid Entry");
- return locator;
+ public AdaptablePQEntry(K key, V value, int j) {
+ super(key, value);
+ index = j;
}
- //Exchanges the entries at indices i and j of the array list
- protected void swap (int i, int j){
- super.swap(i,j); //perform the swap
- ((AdaptablePQEntry) heap.get(i)).setIndex(i); //reset entry's index
- ((AdaptablePQEntry) heap.get(j)).setIndex(j); //reset entry's index
+ public int getIndex() {
+ return index;
}
- //Restores the heap property by moving the entry at index j upward/downward
- protected void bubble (int j){
- if (j > 0 && compare(heap.get(j),heap.get(parent(j))) < 0)
- upheap(j);
- else
- downheap(j);
+ public void setIndex(int j) {
+ index = j;
}
+ } // end of nested Adaptable PQEntry class
- //Inserts a key-value pair and returns the entry created
- public Entry insert (K key, V value) throws IllegalArgumentException{
- checkKey(key);
- Entry newest = new AdaptablePQEntry<>(key,value,heap.size());
- heap.add(newest); //add to the end of list
- upheap(heap.size()-1); //upheap newly added entry
- return newest;
- }
+ // Creates an empty adaptable priority queue using natural ordering of keys
+ public HeapAdaptablePriorityQueue() {
+ super();
+ }
- //Removes the given entry from the priority queue
- public void remove (Entry entry) throws IllegalArgumentException{
- AdaptablePQEntry locator = validate(entry);
- int j = locator.getIndex();
- if (j == heap.size()-1) //entry is at last position
- heap.remove(heap.size()-1); //so just remove it
- else {
- swap(j, heap.size()-1); //swap entry to last position
- heap.remove(heap.size()-1); //then remove it
- bubble(j); //and fix entry displayed by the swap
- }
- }
+ // Creates an empty adaptable priority queue using the given comparator
+ public HeapAdaptablePriorityQueue(Comparator comp) {
+ super(comp);
+ }
+
+ // Validates an entry to ensure it is location-aware
+ protected AdaptablePQEntry validate(Entry entry) throws IllegalArgumentException {
+ if (!(entry instanceof AdaptablePQEntry)) throw new IllegalArgumentException("Invalid Entry");
+ AdaptablePQEntry locator = (AdaptablePQEntry) entry;
+ int j = locator.getIndex();
+ if (j >= heap.size() || heap.get(j) != locator)
+ throw new IllegalArgumentException("Invalid Entry");
+ return locator;
+ }
- //Replaces the key of an entry
- public void replaceKey (Entry entry, K key) throws IllegalArgumentException{
- AdaptablePQEntry locator = validate(entry);
- checkKey(key);
- locator.setKey(key); //method inherited from PQEntry
- bubble(locator.getIndex()); //with new key, may need to move entry
+ // Exchanges the entries at indices i and j of the array list
+ protected void swap(int i, int j) {
+ super.swap(i, j); // perform the swap
+ ((AdaptablePQEntry) heap.get(i)).setIndex(i); // reset entry's index
+ ((AdaptablePQEntry) heap.get(j)).setIndex(j); // reset entry's index
+ }
+
+ // Restores the heap property by moving the entry at index j upward/downward
+ protected void bubble(int j) {
+ if (j > 0 && compare(heap.get(j), heap.get(parent(j))) < 0) upheap(j);
+ else downheap(j);
+ }
+
+ // Inserts a key-value pair and returns the entry created
+ public Entry insert(K key, V value) throws IllegalArgumentException {
+ checkKey(key);
+ Entry newest = new AdaptablePQEntry<>(key, value, heap.size());
+ heap.add(newest); // add to the end of list
+ upheap(heap.size() - 1); // upheap newly added entry
+ return newest;
+ }
+
+ // Removes the given entry from the priority queue
+ public void remove(Entry entry) throws IllegalArgumentException {
+ AdaptablePQEntry locator = validate(entry);
+ int j = locator.getIndex();
+ if (j == heap.size() - 1) // entry is at last position
+ heap.remove(heap.size() - 1); // so just remove it
+ else {
+ swap(j, heap.size() - 1); // swap entry to last position
+ heap.remove(heap.size() - 1); // then remove it
+ bubble(j); // and fix entry displayed by the swap
}
+ }
+
+ // Replaces the key of an entry
+ public void replaceKey(Entry entry, K key) throws IllegalArgumentException {
+ AdaptablePQEntry locator = validate(entry);
+ checkKey(key);
+ locator.setKey(key); // method inherited from PQEntry
+ bubble(locator.getIndex()); // with new key, may need to move entry
+ }
}
diff --git a/src/graphvisualizer/graph/HeapPriorityQueue.java b/src/graphvisualizer/graph/HeapPriorityQueue.java
index 923a6b2..e5d9613 100644
--- a/src/graphvisualizer/graph/HeapPriorityQueue.java
+++ b/src/graphvisualizer/graph/HeapPriorityQueue.java
@@ -3,96 +3,105 @@
import java.util.ArrayList;
import java.util.Comparator;
-//An implementation of a priority queue using an array-based heap
-public class HeapPriorityQueue extends AbstractPriorityQueue{
- //primary collection of priority queue entries
- protected ArrayList> heap = new ArrayList<>();
- //create an empty priority queue based on the natural ordering of its keys
- public HeapPriorityQueue(){super();}
- //create an empty priority queue using the given comparator to order keys
- public HeapPriorityQueue(Comparator comp){super(comp);}
-
- //protected utilities
- protected int parent(int j){
- return (j-1)/2;
- } //truncating division
- protected int left (int j){
- return 2*j+1;
- }
- protected int right (int j){
- return 2*j+2;
- }
- protected boolean hasLeft(int j){
- return left(j) < heap.size();
- }
- protected boolean hasRight(int j){
- return right(j) < heap.size();
- }
+// An implementation of a priority queue using an array-based heap
+public class HeapPriorityQueue extends AbstractPriorityQueue {
+ // primary collection of priority queue entries
+ protected ArrayList> heap = new ArrayList<>();
- //Exchanges the entries at indices i and j of the array list
- protected void swap(int i, int j){
- Entry temp = heap.get(i);
- heap.set(i, heap.get(j));
- heap.set(j, temp);
- }
+ // create an empty priority queue based on the natural ordering of its keys
+ public HeapPriorityQueue() {
+ super();
+ }
- //Moves the entry at index j higher, if necessary, to restore the heap property
- protected void upheap (int j){
- while (j>0){ //continue until reaching root (or break statement)
- int p = parent(j);
- if (compare(heap.get(j), heap.get(p)) >= 0) break; //heap property verified
- swap(j, p);
- j = p; //continue from the parent's location
- }
- }
+ // create an empty priority queue using the given comparator to order keys
+ public HeapPriorityQueue(Comparator comp) {
+ super(comp);
+ }
- //Moves the entry at index j lower, if necessary, to restore the heap property
- protected void downheap (int j){
- while (hasLeft(j)){ //continue to bottom (or break statement)
- int leftIndex = left(j);
- int smallChildIndex = leftIndex; //although right may be smaller
- if (hasRight(j)){
- int rightIndex = right(j);
- if (compare(heap.get(leftIndex), heap.get(rightIndex)) > 0)
- smallChildIndex = rightIndex; //right child is smaller
- }
- if (compare(heap.get(smallChildIndex), heap.get(j)) >= 0)
- break; //heap property has been restored
- swap(j, smallChildIndex);
- j = smallChildIndex; //continue at position of the child
- }
- }
+ // protected utilities
+ protected int parent(int j) {
+ return (j - 1) / 2;
+ } // truncating division
- //Returns the number of items in the priority queue
- public int size(){
- return heap.size();
- }
+ protected int left(int j) {
+ return 2 * j + 1;
+ }
- //Returns (but does not remove) an entry with minimal key (if any)
- public Entry min() {
- if (heap.isEmpty())
- return null;
- return heap.get(0);
+ protected int right(int j) {
+ return 2 * j + 2;
+ }
+
+ protected boolean hasLeft(int j) {
+ return left(j) < heap.size();
+ }
+
+ protected boolean hasRight(int j) {
+ return right(j) < heap.size();
+ }
+
+ // Exchanges the entries at indices i and j of the array list
+ protected void swap(int i, int j) {
+ Entry temp = heap.get(i);
+ heap.set(i, heap.get(j));
+ heap.set(j, temp);
+ }
+
+ // Moves the entry at index j higher, if necessary, to restore the heap property
+ protected void upheap(int j) {
+ while (j > 0) { // continue until reaching root (or break statement)
+ int p = parent(j);
+ if (compare(heap.get(j), heap.get(p)) >= 0) break; // heap property verified
+ swap(j, p);
+ j = p; // continue from the parent's location
}
+ }
- //Inserts a key-value pair and returns the entry created
- public Entry insert(K key, V value) throws IllegalArgumentException {
- checkKey(key); //auxiliary key-checking method (could throw exception)
- Entry newest = new PQEntry<>(key, value);
- heap.add(newest); //add to the end of the list
- upheap(heap.size()-1); //upheap newly added entry
- return newest;
+ // Moves the entry at index j lower, if necessary, to restore the heap property
+ protected void downheap(int j) {
+ while (hasLeft(j)) { // continue to bottom (or break statement)
+ int leftIndex = left(j);
+ int smallChildIndex = leftIndex; // although right may be smaller
+ if (hasRight(j)) {
+ int rightIndex = right(j);
+ if (compare(heap.get(leftIndex), heap.get(rightIndex)) > 0)
+ smallChildIndex = rightIndex; // right child is smaller
+ }
+ if (compare(heap.get(smallChildIndex), heap.get(j)) >= 0)
+ break; // heap property has been restored
+ swap(j, smallChildIndex);
+ j = smallChildIndex; // continue at position of the child
}
+ }
+
+ // Returns the number of items in the priority queue
+ public int size() {
+ return heap.size();
+ }
+
+ // Returns (but does not remove) an entry with minimal key (if any)
+ public Entry min() {
+ if (heap.isEmpty()) return null;
+ return heap.get(0);
+ }
+
+ // Inserts a key-value pair and returns the entry created
+ public Entry insert(K key, V value) throws IllegalArgumentException {
+ checkKey(key); // auxiliary key-checking method (could throw exception)
+ Entry newest = new PQEntry<>(key, value);
+ heap.add(newest); // add to the end of the list
+ upheap(heap.size() - 1); // upheap newly added entry
+ return newest;
+ }
- //Removes and returns an entry with minimal key (if any)
- public Entry removeMin() {
- if (heap.isEmpty()) {
- return null;
- }
- Entry answer = heap.get(0);
- swap(0,heap.size()-1);
- heap.remove(heap.size()-1);
- downheap(0);
- return answer;
+ // Removes and returns an entry with minimal key (if any)
+ public Entry removeMin() {
+ if (heap.isEmpty()) {
+ return null;
}
+ Entry answer = heap.get(0);
+ swap(0, heap.size() - 1);
+ heap.remove(heap.size() - 1);
+ downheap(0);
+ return answer;
+ }
}
diff --git a/src/graphvisualizer/graph/InvalidEdgeException.java b/src/graphvisualizer/graph/InvalidEdgeException.java
index f7d4bd6..c7cfacf 100644
--- a/src/graphvisualizer/graph/InvalidEdgeException.java
+++ b/src/graphvisualizer/graph/InvalidEdgeException.java
@@ -1,11 +1,11 @@
package graphvisualizer.graph;
public class InvalidEdgeException extends RuntimeException {
- public InvalidEdgeException() {
- super("The edge is invalid or does not belong to this graph.");
- }
+ public InvalidEdgeException() {
+ super("The edge is invalid or does not belong to this graph.");
+ }
- public InvalidEdgeException(String string) {
- super(string);
- }
+ public InvalidEdgeException(String string) {
+ super(string);
+ }
}
diff --git a/src/graphvisualizer/graph/InvalidVertexException.java b/src/graphvisualizer/graph/InvalidVertexException.java
index c38d191..ea598e8 100644
--- a/src/graphvisualizer/graph/InvalidVertexException.java
+++ b/src/graphvisualizer/graph/InvalidVertexException.java
@@ -1,11 +1,11 @@
package graphvisualizer.graph;
public class InvalidVertexException extends RuntimeException {
- public InvalidVertexException() {
- super("The vertex is invalid or does not belong to this graph.");
- }
+ public InvalidVertexException() {
+ super("The vertex is invalid or does not belong to this graph.");
+ }
- public InvalidVertexException(String string) {
- super(string);
- }
+ public InvalidVertexException(String string) {
+ super(string);
+ }
}
diff --git a/src/graphvisualizer/graph/PriorityQueue.java b/src/graphvisualizer/graph/PriorityQueue.java
index de09ca0..98a9d1c 100644
--- a/src/graphvisualizer/graph/PriorityQueue.java
+++ b/src/graphvisualizer/graph/PriorityQueue.java
@@ -1,10 +1,14 @@
package graphvisualizer.graph;
-//Interface for the priority queue ADT
-public interface PriorityQueue {
- int size();
- boolean isEmpty();
- Entry insert(K key, V value) throws IllegalArgumentException;
- Entry min();
- Entry removeMin();
+// Interface for the priority queue ADT
+public interface PriorityQueue {
+ int size();
+
+ boolean isEmpty();
+
+ Entry insert(K key, V value) throws IllegalArgumentException;
+
+ Entry min();
+
+ Entry removeMin();
}
diff --git a/src/graphvisualizer/graph/Vertex.java b/src/graphvisualizer/graph/Vertex.java
index 2046c29..74f5539 100644
--- a/src/graphvisualizer/graph/Vertex.java
+++ b/src/graphvisualizer/graph/Vertex.java
@@ -1,6 +1,6 @@
package graphvisualizer.graph;
public interface Vertex {
- /* return element stored in vertex */
- V element();
+ /* return element stored in vertex */
+ V element();
}
diff --git a/src/graphvisualizer/graphalgorithms/CycleDetection.java b/src/graphvisualizer/graphalgorithms/CycleDetection.java
index 1e0e26a..ee12499 100644
--- a/src/graphvisualizer/graphalgorithms/CycleDetection.java
+++ b/src/graphvisualizer/graphalgorithms/CycleDetection.java
@@ -7,118 +7,151 @@
import java.util.*;
/**
- * A cycle detection algorithm that can be used on a directed graph
- * that is strongly connected or not strongly connected with random
- * generation of directed edges.
+ * A cycle detection algorithm that can be used on a directed graph that is strongly connected or
+ * not strongly connected with random generation of directed edges.
*/
public class CycleDetection {
- /*
- These 2 variables are declared as global variables since it's hard to
- pass primitive datatype by reference as they are immutable. The only
- way to pass them by reference without using other datatype in external
- libraries is to create a class to wrap the primitive datatype, however,
- since this is not our primary concern in detecting a cycle, both variables
- are merely declared as global variables.
- */
- private static boolean isCyclic;
- private static int cycleCount;
+ /*
+ These 2 variables are declared as global variables since it's hard to
+ pass primitive datatype by reference as they are immutable. The only
+ way to pass them by reference without using other datatype in external
+ libraries is to create a class to wrap the primitive datatype, however,
+ since this is not our primary concern in detecting a cycle, both variables
+ are merely declared as global variables.
+ */
+ private static boolean isCyclic;
+ private static int cycleCount;
- /**
- * Construct a visualization of cycle detection algorithm in a directed graph (strongly connected/not
- * strongly connected) referenced by digraph
. Random directed edges will be generated until
- * a cycle is found.
- *
- * @param digraph Directed graph
- * @param graphView Graph visualization object
- * @return A general description of the process and result of the cycle detection algorithm
- */
- public static String start(AdjacencyMapDigraph digraph, SmartGraphPanel graphView) {
- LinkedList> vertices = new LinkedList<>();
- Set> visitedVertices = new HashSet<>();
- Set> onStackVertices = new HashSet<>();
- Map, Vertex> parentsOfVertices = new HashMap<>();
- LinkedList>> foundCycles = new LinkedList<>();
- isCyclic = false;
- cycleCount = 0;
- StringBuilder sb = new StringBuilder();
- StringBuilder buf = new StringBuilder();
+ /**
+ * Construct a visualization of cycle detection algorithm in a directed graph (strongly
+ * connected/not strongly connected) referenced by digraph
. Random directed edges
+ * will be generated until a cycle is found.
+ *
+ * @param digraph Directed graph
+ * @param graphView Graph visualization object
+ * @return A general description of the process and result of the cycle detection algorithm
+ */
+ public static String start(
+ AdjacencyMapDigraph digraph, SmartGraphPanel graphView) {
+ LinkedList> vertices = new LinkedList<>();
+ Set> visitedVertices = new HashSet<>();
+ Set> onStackVertices = new HashSet<>();
+ Map, Vertex> parentsOfVertices = new HashMap<>();
+ LinkedList>> foundCycles = new LinkedList<>();
+ isCyclic = false;
+ cycleCount = 0;
+ StringBuilder sb = new StringBuilder();
+ StringBuilder buf = new StringBuilder();
- while(!isCyclic) {
- vertices.addAll(digraph.vertices());
+ while (!isCyclic) {
+ vertices.addAll(digraph.vertices());
- while (!vertices.isEmpty()) { //continue perform DFS if there are unvisited vertices, e.g. when there are several strongly connected components
- checkCycle(digraph, vertices.remove(), vertices, visitedVertices, onStackVertices, parentsOfVertices, foundCycles, buf, graphView);
- visitedVertices.clear(); parentsOfVertices.clear();
- }
- if(!isCyclic) {
- sb.append(digraph.generateRandomEdge(new Random().nextInt(20) + 1)); //generate a random edge
- }
- }
- return sb.append(String.format("\n[Cycle Detection] [%d cycle(s) found.]", cycleCount)).append(buf).append("\n").toString();
+ while (!vertices
+ .isEmpty()) { // continue perform DFS if there are unvisited vertices, e.g. when there are
+ // several strongly connected components
+ checkCycle(
+ digraph,
+ vertices.remove(),
+ vertices,
+ visitedVertices,
+ onStackVertices,
+ parentsOfVertices,
+ foundCycles,
+ buf,
+ graphView);
+ visitedVertices.clear();
+ parentsOfVertices.clear();
+ }
+ if (!isCyclic) {
+ sb.append(
+ digraph.generateRandomEdge(new Random().nextInt(20) + 1)); // generate a random edge
+ }
}
+ return sb.append(String.format("\n[Cycle Detection] [%d cycle(s) found.]", cycleCount))
+ .append(buf)
+ .append("\n")
+ .toString();
+ }
- /**
- * A DFS method to detect the existence of a cycle in the directed graph. Random directed edges will be generated until
- * a cycle is found. This should be called repeatedly by