PDA

View Full Version : Java graph work problems

CSJoe
Jan 15, 2007, 11:58 AM
Having a spot of bother getting my head round this baby. Any suggestions?
You should use Hierholzers Algorithm to find the Euler tour

The program should be started with the command:
java -classpath \\raptor\files\packages\java\repository;. EulerGraph <graph name>
For example: java -classpath \\raptor\files\packages\java\repository;. EulerGraph graph.adj

You should load in a graph file, which simply contains a list of edges, edges are pairs of nodes labels (arbitrary alphanumeric strings) separated by a colon, For example graph.adj might contain:
10:15
15:27
27:10

You should output a file named after the input file name with an additional .euler extension. This should contain either the text FAIL if there is no tour or a list [Node1, Node2, ..., NodeX, Node1] which describes a Euler Tour in the given graph. The list must be surrounded by square brackets and the nodes must be divided by commas. For example graph.adj.euler might contain:
[10, 15, 27, 10] or [15, 10, 27, 15]

Because there are many possible Euler tours in a given Eulerian graph, any one of the possible trails is acceptable. No other text should be present in the output file.

You should generate your own set of test data to check that your program works, including large Eulerian graphs (so that the sub trails are present) and non Eulerian graphs, empty graphs and minimal graphs.

The prj.graph package contains the three classes
package pjr.graph;

import java.util.*;
import java.io.*;

/**
* This is a graph containing nodes and edges.
* <p>
* The graph can be used for both directed and undirected graphs.
* The current interpretation of undirected edges in the
* algorithms is being able to traverse a single edge in either
* direction. This is reflected in the graph and edge access functions,
* which provide for this form of undirected access.
* <p>
* Consistency of the graph takes several forms:
* all nodes and edges attach to items in the graph;
* unique nodes and edges in the collections (no duplicate objects);
* edges having a connection at each end; and
* edge to and from corresponding to node to and from.
* <p>
* Consistency is maintained through the operations in graph, so
* that its not possible to add an edge without the nodes being
* in the graph.
* Also, the node delete removes any connecting edges from the graph
* <p>
* Note that it is still possible to create an inconsistent graph by
* accessing fields directly, or via poor use of Node or Edge methods.
*
* @see Node
* @see Edge
* @author Peter Rodgers
*
*/
public class Graph {

/** Collection of nodes. */
private ArrayList<Node> nodes = new ArrayList<Node>();
/** Collection of edges. */
private ArrayList<Edge> edges = new ArrayList<Edge>();
/** Graph label, can be empty. */
private String label = "";
/** Separator between nodes in an adjacency list file */
public final char ADJACENCYSEPARATOR = ':';

/** Minimal constructor. It creates an empty unlabeled graph*/
public Graph() {}
/** Trivial constructor. It creates an empty labeled graph */
public Graph(String inLabel) {setLabel(inLabel);}

/** Trival accessor. */
public String getLabel() {return label;}
/** Trivial modifier. */
public void setLabel(String inLabel) {label=inLabel;}

/**
* Adds a node to the graph.
* @return true if the node is added, false if it fails because it already there.
*/
public boolean addNode(Node n) {

if (containsNode(n)) {
return(false);
}
}

/**
* Adds an edge to the graph.
* @return true if the node is added, false if it fails because the edge is
* already there, or either node is not in the graph.
*/
public boolean addEdge(Edge e) {

if(!containsNode(e.getTo())) {
return(false);
}
if(!containsNode(e.getFrom())) {
return(false);
}

if(containsEdge(e)) {
return(false);
}

}

/** Trivial accessor */
public ArrayList<Node> getNodes() {return nodes;}

/** Trivial accessor */
public ArrayList<Edge> getEdges() {return edges;}

/**
* Set the visited fields of all the nodes in the graph to false.
* this, or the one argument alternative should be called at the
* start of an algorithm which uses the visited flags of nodes.
*/
public void setNodesVisited() {
setNodesVisited(getNodes(),false);
}

/**
* Set the visited fields of all the nodes in the graph with the argument.
*/
public void setNodesVisited(boolean inVisited) {
setNodesVisited(getNodes(),inVisited);
}

/**
* Set the visited fields of the given nodes with the argument.
*/
public void setNodesVisited(Collection<Node> nodes, boolean inVisited) {
Iterator<Node> ni = nodes.iterator();
while(ni.hasNext()) {
Node n = ni.next();
n.setVisited(inVisited);
}
}

/**
* Set the visited values of the edges to false,
* this should be called before using the
* visited flags of nodes.
*/
public void setEdgesVisited() {
setEdgesVisited(getEdges(),false);
}

/**
* Set the visited values of all the edges in the graph to the argument.
*/
public void setEdgesVisited(boolean inVisited) {
setEdgesVisited(getEdges(),inVisited);
}

/**
* Set the visited values of the given edges to the argument.
*/
public void setEdgesVisited(Collection<Edge> edges, boolean inVisited) {
Iterator<Edge> ei = edges.iterator();
while(ei.hasNext()) {
Edge e = ei.next();
e.setVisited(inVisited);
}
}

/** Gives the nodes that are not marked as visited. */
public HashSet<Node> unvisitedNodes() {
HashSet<Node> ret = new HashSet<Node>();

Iterator<Node> ni = nodes.iterator();
while(ni.hasNext()) {
Node n = ni.next();
if(n.getVisited() == false) {
}
}

return(ret);
}

/** Gives the nodes that are marked as visited. */
public HashSet<Node> visitedNodes() {
HashSet<Node> ret = new HashSet<Node>();

Iterator<Node> ni = nodes.iterator();
while(ni.hasNext()) {
Node n = ni.next();
if(n.getVisited() != false) {
}
}

return(ret);
}

/**
* Set the paths of all the nodes in the graph with null.
* This should be called at the
* start of an algorithm which uses the path fields of nodes.
*/
public void setNodesPaths() {
setNodesPaths(getNodes(),null);

}

/**
* Set the paths of all the nodes in the graph with the given path.
*/
public void setNodesPaths(AbstractList path) {
setNodesPaths(getNodes(),path);
}

/**
* Set the given nodes path fields to the given list.
*/
public void setNodesPaths(Collection<Node> nodes, AbstractList path) {
Iterator<Node> ni = nodes.iterator();
while(ni.hasNext()) {
Node n = ni.next();
n.setPath(path);
}
}

/** Gives the edges that are not marked as visited. */
public HashSet<Edge> unvisitedEdges() {
HashSet<Edge> ret = new HashSet<Edge>();

Iterator<Edge> ei = edges.iterator();
while(ei.hasNext()) {
Edge e = ei.next();
if(e.getVisited() == false) {
}
}

return(ret);
}

/** Gives the edges that are marked as visited. */
public HashSet<Edge> visitedEdges() {
HashSet<Edge> ret = new HashSet<Edge>();

Iterator<Edge> ei = edges.iterator();
while(ei.hasNext()) {
Edge e = ei.next();
if(e.getVisited() != false) {
}
}

return(ret);
}

/**
* Sum all the edge weights in the graph.
*/
public double sumEdgeWeights() {
return(sumEdgeWeights(getEdges()));
}

/**
* Sum the edge weights of edges in the given collection.
*/
public double sumEdgeWeights(Collection<Edge> edges) {

double sum = 0.0;
Iterator<Edge> ei = edges.iterator();
while(ei.hasNext()) {
Edge e = ei.next();
sum += e.getWeight();
}
return(sum);
}

/**
* Finds if the node is already present in the graph.
*/
public boolean containsNode(Node n) {
Iterator<Node> ni = nodes.iterator();
while(ni.hasNext()) {
if(n == ni.next()) {
return(true);
}
}
return(false);
}

/**
* Finds if the edge is already present in the graph.
*/
public boolean containsEdge(Edge e) {
Iterator<Edge> ei = edges.iterator();
while(ei.hasNext()) {
if(e == ei.next()) {
return(true);
}
}
return(false);
}

/**
* Removes the node from the graph and deletes any connecting edges. Accounts
* for redundant data connecting nodes.
* @return the success of the operation, failure is due to node not being in the graph.
*/
public boolean removeNode(Node removeNode) {

if(!containsNode(removeNode)) {
return(false);
}

HashSet<Edge> edges = removeNode.connectingEdges();
Iterator<Edge> ei = edges.iterator();
while(ei.hasNext()) {
Edge e = ei.next();
removeEdge(e);
}

nodes.remove(removeNode);

return(true);
}

/**
* Removes the nodes with the given label from the graph and removes
* any connecting edges. Accounts for redundant data connecting nodes.
* @return the success of the operation, false if there is no node
* with the label in the graph.
*/
public boolean removeNode(String removeString) {

boolean ret = false;

boolean delete = true;
while(delete) {
delete = false;
Iterator<Node> ni = nodes.iterator();
while (ni.hasNext() && !delete) {
Node n = ni.next();
if (removeString.equals(n.getLabel())) {
removeNode(n);
delete = true;
ret = true;
}
}
}

return(ret);
}

/**
* Removes the given node collection. Does nothing if the elements
* in the collection are not nodes in the graph.
*/
public void removeNodes(Collection<Node> c) {
Iterator<Node> ni = c.iterator();
while(ni.hasNext()) {
Node n = ni.next();
removeNode(n);
}
}

/**
* Removes the given edge collection. Does nothing if the elements
* in the collection are not edges in the graph.
*/
public void removeEdges(Collection<Edge> c) {
Iterator<Edge> ei = c.iterator();
while(ei.hasNext()) {
Edge e = ei.next();
removeEdge(e);
}
}

/**
* Removes the edge from the graph. Accounts
* for redundant data connecting nodes.
* @return the success of the operation, failure is due to edge not being in the graph.
*/
public boolean removeEdge(Edge removeEdge) {

if(!containsEdge(removeEdge)) {
return(false);
}

// this is the best I can do - set the source and target of the
// connecting edge to null, if there are any external references
// to the edge, then their attempt to access the nodes at the ends
// may crash.

removeEdge.setFromTo(null,null);
edges.remove(removeEdge);

return(true);
}

/**
* Removes the nodes and edges from the graph, leaving an empty graph.
* This is a destructive clear as the nodes are disconnected from the
* edges, but not deleted.
*/
public void clear() {
Iterator<Node> ni = nodes.iterator();
while(ni.hasNext()) {
Node n = ni.next();
removeNode(n);
ni = nodes.iterator();
}

}

/**
* @return the first node in the nodeList that has the given label, or null if there is no such node.
*/
public Node nodeWithLabel(String nodeLabel) {
Iterator<Node> ni = getNodes().iterator();
while(ni.hasNext()) {
Node node = ni.next();
if(nodeLabel.equals(node.getLabel())) {
return node;
}
}
return null;
}

/**
* This saves an adjacency list graph file. The file is in the form of a
* simple adjacency list, each line
* of the file is an edge, with nodes separated by the {@link #ADJACENCYSEPARATOR}
* character. Any empty line
* or line with more than one colon is ignored.
* Nodes are assumed to have unique labels for the purpose of this file writer
* if there are duplicates, they will be merged to the same node.
*/
public void saveAdjacencyFile(String fileName) {
try {
BufferedWriter b = new BufferedWriter(new FileWriter(fileName));
HashSet<Node> remainingNodes = new HashSet<Node>(getNodes());
StringBuffer s = new StringBuffer();
Iterator<Edge> ei = getEdges().iterator();
while (ei.hasNext()){
Edge e = ei.next();
s.setLength(0);
Node n1 = e.getFrom();
Node n2 = e.getTo();
b.write(s.toString());
b.newLine();

remainingNodes.remove(n1);
remainingNodes.remove(n2);
}
//deal with singleton nodes
Iterator<Node> ni = remainingNodes.iterator();
while (ni.hasNext()){
Node n = ni.next();
b.write(n.toString());
b.newLine();
}

b.close();
}
catch(IOException e){
System.out.println("An IO exception occured when executing saveAdjacencyFile("+fileName+") in Graph.java: "+e+"\n");
System.exit(1);
}
}

/**
* This loads the given adjacency list graph file into the graph, deleting any
* current nodes and edges. The file is in the form of a simple adjacency list, each line
* of the file is an edge, with nodes separated by the {@link #ADJACENCYSEPARATOR}
* character. Any empty line or line with more than one colon is ignored.
* Any non empty line without a colon is
* considered to be a node with no connecting edges.
* Nodes are assumed to have unique labels for the purpose of this loader.
* @return true if successful, false if there was a formatting problem
*/

clear();
try {
String line = b.readLine();
while(line != null) {

int separatorInd = line.indexOf(ADJACENCYSEPARATOR);

// ignore any empty lines and lines with more than 1 separator
if(line.length() > 0 && separatorInd == line.lastIndexOf(ADJACENCYSEPARATOR)) {
if(separatorInd >= 0) {
String n1 = line.substring(0,separatorInd);
String n2 = line.substring(separatorInd+1);
} else {
// no separator, so just add a singleton node
}
}
}

b.close();

} catch(IOException e){
System.out.println("An IO exception occured when executing loadAdjacencyFile("+fileName+") in Graph.java: "+e+"\n");
System.exit(1);
}

return(true);
}

/**
* Creates an edge between the nodes with the given labels. This is the unweighted
* unlabelled edge version of the method.
* @return the created edge, or null if was not created.
*/
public Edge addAdjacencyEdge(String fromLabel, String toLabel) {
}

/**
* Creates an edge between the nodes with the given labels. This is the
* unlabeled edge version of the method.
* @return the created edge, or null if was not created.
*/
public Edge addAdjacencyEdge(String fromLabel, String toLabel, double edgeWeight) {
}

/**
* Creates an edge between the nodes with the given labels. This is the unweighted version
* of the method.
* @return the created edge, or null if was not created.
*/
public Edge addAdjacencyEdge(String fromLabel, String toLabel, String edgeLabel) {
}

/**
* Creates an edge between the nodes with the given labels, creating the nodes if needed.
* If a node label is empty, the node is not created. If one or both the labels are empty, the
* edge is not created. Self sourcing and parallel edges are allowed. Third argument is the
* edge label, fourth is the edge weight.
* @return the created edge, or null if was not created.
*/
public Edge addAdjacencyEdge(String fromLabel, String toLabel, String edgeLabel, double edgeWeight) {

Node fromNode = null;
Node toNode = null;

if(!fromLabel.equals("")) {
}

if(!toLabel.equals("")) {
}

if(fromNode != null && toNode != null) {

Edge e = new Edge(fromNode, toNode, edgeLabel, edgeWeight);
return(e);
}

return(null);
}

/**
* Either returns an existing node with the label, or if there is none
* creates a node with the label and adds it to the graph.
* @return the found or created node, or null if there is more than one node with the label.
*/

Node returnNode = null;
Iterator<Node> ni = nodes.iterator();
while(ni.hasNext()) {
Node n = ni.next();
if(label.equals(n.getLabel())) {
if(returnNode != null) {
return(null);
}
returnNode = n;
}
}
if (returnNode != null) {
return(returnNode);
}

Node newNode = new Node(label);

return(newNode);
}

/**
* Generates a random graph of the size of nodes and edges passed. It
* does this by generating edges between random nodes, which are labeled
* with the relevant numbers. Only these attached nodes get created.
* The old graph gets deleted.
*/
public void generateRandomGraph(int nodeNumber, int edgeNumber) {

clear();
int num = 0;
Random r = new Random();
for(int i = 0; i < edgeNumber; i++) {
Integer node1 = new Integer(r.nextInt(nodeNumber));
Integer node2 = new Integer(r.nextInt(nodeNumber));
}
}

/**
* Check graph consistency by ensuring internal data structures are correct.
* That is: all redundant connection data is correct and check all connecting
* nodes and edges are in the graph.
* This method is a useful test to ensure that internal methods that
* change the graph leave a valid graph.
*/
public boolean consistent() {

// go though nodes checking parent and all to and from vectors
// correspond to connecting edges

Iterator<Node> ni = nodes.iterator();
while(ni.hasNext()) {
Node n = ni.next();
if(!n.consistent(this)) {return false;}
}

// go through edges checking parent and all connecting ids are
// in to and from vectors

Iterator<Edge> ei = edges.iterator();
while(ei.hasNext()) {
Edge e = ei.next();
if(!e.consistent(this)) {return false;}
}

return(true);
}

/**
* Outputs the node and edge lists in a string.
*/
public String toString() {
return(getLabel()+"\nNodes:"+getNodes().toString()+"\nEdges:"+getEdges().toString());
}

}

package pjr.graph;

import java.util.*;
import java.io.*;

/**
* A node in a graph. This implements a simple labeled node for a graph.
* <p>
* It contains some additional fields for helping when writing algorithms, the
* boolean {@link #visited}, a flag for indicating that a node has been traversed
* and the list {@link #path} for indicating some sort of route to the
* node, which also allows a test (null) to see if the node has been visited.
* <p>
* A redundant structure is used to speed up the access of neighbouring
* nodes. This is in the form of the two Hash Sets, {@link #edgesFrom} and
* {@link #edgesTo}, which are modified when edges are created, deleted or modified.
*
* @see Graph
* @see Edge
* @author Peter Rodgers
*/
public class Node {

/**
* Redundant data giving the edges out of this node to speed up algorithms.
* It needs to be maintained by edges as they are connected and
* removed from this node. The node should not alter this member.
* The collection should have unique content so that an edge must appear only once.
*/
private HashSet<Edge> edgesFrom = new HashSet<Edge>();
/**
* Redundant data giving the edges into this node to speed up algorithms.
* It needs to be maintained by edges as they are connected and
* removed from this node. The node should not alter this member.
* The collection should have unique content so that an edge must appear only once.
*/
private HashSet<Edge> edgesTo = new HashSet<Edge>();

/** Label, can be empty. */
private String label = "";
/** This flag that can be set if the node has been traversed in an algorithm. */
private boolean visited = false;
/**
* A variable for use in graph algorithms. This list allows a path of
* the users devising to be associated with a node, perhaps containing
* nodes or edges (or both). It can also be used to find out if the node
* has been visited, as it should be set to null if it has not.
*/
private AbstractList path = null;

/** Minimal constructor. It creates an unlabeled node. */
public Node() {}

/** Creates a labeled node */
public Node(String inLabel) {
setLabel(inLabel);
}

/** Trival accessor. */
public HashSet<Edge> getEdgesFrom() {return edgesFrom;}
/** Trival accessor. */
public HashSet<Edge> getEdgesTo() {return edgesTo;}
/** Trival accessor. */
public String getLabel() {return label;}
/** Trival accessor. */
public boolean getVisited() {return visited;}
/** Trival accessor. */
public AbstractList getPath() {return path;}
/** Trivial modifier. */
public void setLabel(String inLabel) {label=inLabel;}
/** Trivial modifier. */
public void setVisited(boolean inVisited) {visited = inVisited;}
/** Trivial modifier. */
public void setPath(AbstractList inPath) {path = inPath;}

/** This should only be used by an edge method. */
/** This should only be used by an edge method. */
/** This should only be used by an edge method. */
protected boolean removeEdgeFrom(Edge e) {return(edgesFrom.remove(e));}
/** This should only be used by an edge method. */
protected boolean removeEdgeTo(Edge e) {return(edgesTo.remove(e));}

/**
* Gives all the connecting edges. Duplicates
* could be caused by self sourcing edges, and are removed.
* @return all the connecting edges, without duplicates.
*/
public HashSet<Edge> connectingEdges() {

HashSet<Edge> edges = new HashSet<Edge>(getEdgesFrom());
return(edges);
}

/**
* Gives the unvisited connecting edges, without duplicates. The predicate
* is based on the visited field of the edge.
*/
public HashSet<Edge> unvisitedConnectingEdges() {

HashSet<Edge> edges = new HashSet<Edge>();
Collection<Edge> allEdges = connectingEdges();
Iterator<Edge> ei = allEdges.iterator();
while(ei.hasNext()) {
Edge e = ei.next();
if(!e.getVisited()) {
}
}

return(edges);
}

/**
* Gives all the connecting nodes without duplicates.
* Or, put another way all the neigbouring nodes.
* Duplicates could be due to self sourcing edges or parallel nodes, and are removed.
* @return all the neigbouring nodes, without duplicates.
*/
public HashSet<Node> connectingNodes() {

HashSet<Node> nodes = new HashSet<Node>(degree());
// iterate through the edges
Collection<Edge> edges = connectingEdges();

Iterator<Edge> ei = edges.iterator();
while(ei.hasNext()) {
Node n;
Edge e = ei.next();
// get the node at the right end (this test copes with self sourcing nodes)
if(e.getTo() == this) {
n = e.getFrom();
} else {
n = e.getTo();
}
//check for duplicates
if(!nodes.contains(n)) {
}
}

return(nodes);
}

/**
* Gives all the unvisited connecting nodes, according to the visited field.
* @return all unvisited neighbouring nodes, without duplicates.
*/
public HashSet<Node> unvisitedConnectingNodes() {

HashSet<Node> nodes = new HashSet<Node>(degree());

// iterate through the connecting nodes
Collection<Node> connecting = connectingNodes();
Iterator<Node> ni = connecting.iterator();
while(ni.hasNext()) {

Node n = ni.next();
if(!n.getVisited()) {
}
}

return(nodes);
}

/**
* Gives all the connecting nodes without paths, discarding duplicates.
* Used to get the nodes which have not already been visited when the path field is
* in use.
* @return all pathless neighbouring nodes, without duplicates.
*/
public HashSet<Node> pathlessConnectingNodes() {
HashSet<Node> nodes = new HashSet<Node>(degree());

// iterate through the connecting nodes
Collection<Node> connecting = connectingNodes();
Iterator<Node> ni = connecting.iterator();
while(ni.hasNext()) {
Node n = ni.next();
if(n.getPath() == null) {
}
}

return(nodes);
}

/** Gives the number of connecting edges. */
public int degree() {
return(getEdgesFrom().size()+getEdgesTo().size());
}

/**
* Check consistency- ensure all redundant connection data matches
* with edge to and from. Principally used by the Graph method
*/
public boolean consistent(Graph g) {

// needs to be done twice, once for from list, once for to list
Iterator<Edge> fi = edgesFrom.iterator();
while(fi.hasNext()) {
Edge e = fi.next();
// test for edge having wrong data
if(e.getFrom() != this) {
return false;
}
if(!g.getEdges().contains(e)) {
return false;
}
}

Iterator<Edge> ti = edgesTo.iterator();
while(ti.hasNext()) {
Edge e = ti.next();
// test for edge having wrong data
if(e.getTo() != this) {
return false;
}
if(!g.getEdges().contains(e)) {
return false;
}
}
return true;
}

/** Gives a textual representation of the node, at the moment just the label. */
public String toString() {
return(label);
}
}

package pjr.graph;

import java.util.*;
import java.io.*;

/**
* This is a simple edge, connecting two nodes together in a graph.
* It can be treateded as a directed or undirected edge.
* <p>
* It contains an additional field for helping when writing algorithms, the
* boolean {@link #visited}, a flag for indicating that an edge has been traversed
*
* @see Graph
* @see Node
* @author Peter Rodgers
*/
public class Edge {

/** Source node. Must be assigned.*/
private Node from;
/** Target node. Must be assigned.*/
private Node to;
/** Optional label.*/
private String label = "";
/** Optional weight value.*/
private double weight = 0.0;
/** This flag can be set if the edge has been traversed during a graph algorithm. */
private boolean visited = false;

/**
* Pass the two nodes that the edge connects with to this constructor.
* It creates an edge between the two nodes.
*/
public Edge(Node inFrom, Node inTo) {
setFromTo(inFrom, inTo);
}

/**
* Constructor initialising label.
* It creates an edge between the two nodes.
*/
public Edge(Node inFrom, Node inTo, String inLabel) {
setFromTo(inFrom, inTo);
setLabel(inLabel);
}

/**
* Constructor initialising weight.
* It creates an edge between the two nodes.
*/
public Edge(Node inFrom, Node inTo, double inWeight) {
setFromTo(inFrom, inTo);
setWeight(inWeight);
}

/**
* Constructor initialising label and weight.
* It creates an edge between the two nodes.
*/
public Edge(Node inFrom, Node inTo, String inLabel, double inWeight) {
setFromTo(inFrom, inTo);
setLabel(inLabel);
setWeight(inWeight);
}

/** Trival accessor. */
public Node getFrom() {return from;}
/** Trival accessor. */
/** Trival accessor. */
public String getLabel() {return label;}
/** Trival accessor. */
public double getWeight() {return weight;}
/** Trival accessor. */
public boolean getVisited() {return visited;}
/** Trivial modifier. */
public void setLabel(String inLabel) {label = inLabel;}
/** Trivial modifier. */
public void setWeight(double inWeight) {weight = inWeight;}
/** Trivial modifier. */
public void setVisited(boolean inVisited) {visited = inVisited;}

/** find out if the edge connects to the same node at each end. */
public boolean selfSourcing() {
if(from == to) {
return(true);
}
return(false);
}

/**
* Gives the other end of the edge to the argument node.
* @return the node at the other end of the edge, or null if the passed node is not connected to the edge
*/
public Node getOppositeEnd(Node n) {

Node ret = null;
if (getFrom() == n) {
ret = getTo();
}
if (getTo() == n) {
ret = getFrom();
}

return(ret);
}

/**
* Sets or moves both ends of the edge.
* @return the success of the operation, if fail, then the old state
* should be preserved.
*/
public boolean setFromTo(Node inFrom, Node inTo) {

Node oldFrom=from;
if(!setFrom(inFrom)) {
return(false);
};
if(!setTo(inTo)) {
setFrom(oldFrom);
return(false);
};
return(true);
}

/**
* Sets or moves the source of the edge. Accounts for the
* redundant data in the node. Also deals with nulls, either
* currently attached to edges, or passed to this method.
* @return the success of the operation.
*/
public boolean setFrom(Node inFrom) {
if(from != null) {
if(!from.removeEdgeFrom(this)) {
return(false);
}
}
if(inFrom != null) {
}
from = inFrom;
return(true);
}

/**
* Sets or moves the target of the edge. Accounts for the
* redundant data in the node. Also deals with nulls, either
* currently attached to edges, or passed to this method.
* @return the success of the operation.
*/
public boolean setTo(Node inTo) {
if(to != null) {
if(!to.removeEdgeTo(this)) {
return(false);
}
}
if(inTo != null) {
}
to = inTo;
return(true);
}

/**
* This method reverses the ends of the edge. It also works for undirected edges,
* reversing the from and to values, although in this case no difference should
* be apparent.
*/
public void reverse() {

Node oldFrom = from;
setFrom(to);
setTo(oldFrom);
}

/**
* Checks that the connecting nodes have consistent redundant data. Used principally
* by {@link Graph#consistent}.
*/
public boolean consistent(Graph g) {
if(!getFrom().getEdgesFrom().contains(this)) {
return(false);
}
if(!getTo().getEdgesTo().contains(this)) {
return(false);
}
if(!g.getNodes().contains(getFrom())) {
return(false);
}
if(!g.getNodes().contains(getTo())) {
return(false);
}

return(true);
}

/** Gives the connecting nodes strings in a pair, plus the edge label and weight. */
public String toString() {
return("("+getFrom()+":"+getTo()+","+getLabel()+","+getWeight()+")");
}

}

Long winded i know but I would appreciate the help