I am working on a project in Java that uses a weighted graph to represent a complex family tree, but I have run into problems implementing the basic functionality of the graph. I have 3 classes, a Graph
class, a Node
class that is just a wrapper around some generic member, and a Tester
class. The Graph
class maintains a list of Node
objects, and each Node
keeps a list of the nodes adjacent to it and the weights to each adjacent node. My problem is that, when I create a simple graph that uses spouses and children, I cannot add a child to a node and the parent's spouse. However, if I can add a child to a node, and then a different child to the spouse. For example, I can do this:
A --- B
| |
C D
but I cannot do this:
A --- B
|
C
By cannot do this, I mean that this structure is reflected when I build the graph, but not when I print it. I am stumped, as I cannot find any problems in my code, but I included all 3 classes below. Thank you in advance.
Graph.java
import java.util.HashSet;
public class Graph<T> {
public static double PARENT_TO_CHILD = 1.0;
public static double CHILD_TO_PARENT = -1.0;
public static double SPOUSE_TO_SPOUSE = -0.1;
private Node<T> root;
private HashSet<Node<T>> nodes;
/**
* Creates a graph with the given Node as the root.
*/
public Graph(T root){
this(new Node<T>(root));
}
public Graph(Node<T> root){
this.root = root;
nodes = new HashSet<>();
nodes.add(root);
}
/**
* Adds the given Node or T as a child of the second Node or T.
*
* @param child the Node or T to be added as a child
* @param parent the Node or T to add the child to
*/
public void addChild(T child, T parent){
addChild(new Node<T>(child), findNode(parent));
}
public void addChild(Node<T> child, Node<T> parent){
System.out.println("Adding " + child.toString() + " as a child of " + parent.toString());
addEdge(parent, child, Graph.PARENT_TO_CHILD);
}
/**
* Adds the given Node or T as a parent of the second Node or T.
*
* @param parent the Node or T to be added as a parent
* @param child the Node or T to add the parent to
*/
public void addParent(T parent, T child){
addParent(new Node<T>(parent), findNode(child));
}
public void addParent(Node<T> parent, Node<T> child){
System.out.println("Adding " + parent.toString() + " as a parent of " + child.toString());
addEdge(parent, child, Graph.PARENT_TO_CHILD);
}
/**
* Adds the given node as a spouse of the node with the given name.
*
* @param spouse the node to be added as a spouse
* @param node the Node to add the spouse to
*/
public void addSpouse(T spouse, T member){
addSpouse(new Node<T>(spouse), findNode(member));
}
public void addSpouse(Node<T> spouse, Node<T> node){
System.out.println("Adding " + spouse.toString() + " as a spouse of " + node.toString());
addEdge(node, spouse, Graph.SPOUSE_TO_SPOUSE);
}
/**
* Adds an edge between two Nodes with a weight in the Node objects.
*
* @param n1 the first vertex of the edge
* @param n2 the second vertex of the edge
* @param weight the weight from n1 to n2, inverted when linking the other way
*/
public void addEdge(Node<T> n1, Node<T> n2, double weight){
System.out.println("Adding an edge between " + n1.toString() + " and " + n2.toString() + " with weight " + weight);
n1.addEdge(n2, weight);
n2.addEdge(n1, -weight);
nodes.add(n1);
nodes.add(n2);
}
/**
* Returns a reference to the Node in the graph with the given member.
*
* @param member the member of the Node to find
* @return a reference to the found Node, or null if it was not found
*/
public Node<T> findNode(T member){
System.out.println("Looking for a Node with member: " + member.toString());
for (Node<T> node : nodes)
if (node.equalMembers(member))
return node;
System.out.println("Error: Could not find a node with member " + member.toString() + " in tree.");
return null;
}
/**
* Prints the adjacency lists of each node in the graph and their weight.
*/
public void print(){
System.out.println("\n==================================================");
for (Node<T> node : nodes){
System.out.println("Adjacency list of " + node.toString());
System.out.println(" " + node.adjacentNodesToString());
}
System.out.println("==================================================\n");
}
}
Node.java
import java.util.HashMap;
public class Node<T> {
private HashMap<Node<T>, Double> adjNodes;
private T member;
public Node(T member){
this.member = member;
adjNodes = new HashMap<>();
}
public void addEdge(Node<T> vertex, double weight){
System.out.println("Adding nodewise edge from " + toString() + " to " + vertex.toString() + " with weight " + weight);
adjNodes.put(vertex, weight);
System.out.println("Adjacent nodes of " + toString());
System.out.println(" " + adjacentNodesToString());
}
public double getWeight(Node<T> vertex){
return adjNodes.get(vertex);
}
public String adjacentNodesToString(){
if (adjNodes.size() == 0)
return "None";
String adj = "";
for (Node<T> adjNode : adjNodes.keySet())
adj += adjNode.toString() + " (weight: " + getWeight(adjNode) + ") ";
return adj.substring(0, adj.length()-4);
}
public boolean equalMembers(T otherMem){
return member.equals(otherMem);
}
@Override
public boolean equals(Object obj){
if (obj == null){
return false;
}
if (obj instanceof Node){
Node other = (Node) obj;
return member.equals(other.member);
}
return false;
}
@Override
public int hashCode(){
return member.hashCode();
}
@Override
public String toString(){
return member.toString() + " (" + hashCode() + ")" ;
}
}
Tester.java
public class Tester {
public static void main(String[] args){
graphTest();
}
public static void graphTest(){
// Create the graph with 1 as the root
Graph<Integer> g = new Graph<>(1);
g.print();
// Add 2 as a spouse of 1
g.addSpouse(2, 1);
g.print();
// Add 3 as a child of 1
g.addChild(3, 1);
g.print();
// Add 3 as a child of 2
g.addChild(3, 2); // If this was g.addChild(4, 2) it would be right
g.print();
}
}
Output
==================================================
Adjacency list of 1 (1)
None
==================================================
Looking for a Node with member: 1
Adding 2 (2) as a child of 1 (1)
Adding an edge between 1 (1) and 2 (2) with weight 1.0
Adding nodewise edge from 1 (1) to 2 (2) with weight 1.0
Adjacent nodes of 1 (1)
2 (2) (weight: 1.0)
Adding nodewise edge from 2 (2) to 1 (1) with weight -1.0
Adjacent nodes of 2 (2)
1 (1) (weight: -1.0)
==================================================
Adjacency list of 1 (1)
2 (2) (weight: 1.0)
Adjacency list of 2 (2)
1 (1) (weight: -1.0)
==================================================
Looking for a Node with member: 1
Adding 3 (3) as a child of 1 (1)
Adding an edge between 1 (1) and 3 (3) with weight 1.0
Adding nodewise edge from 1 (1) to 3 (3) with weight 1.0
Adjacent nodes of 1 (1)
2 (2) (weight: 1.0) 3 (3) (weight: 1.0)
Adding nodewise edge from 3 (3) to 1 (1) with weight -1.0
Adjacent nodes of 3 (3)
1 (1) (weight: -1.0)
==================================================
Adjacency list of 1 (1)
2 (2) (weight: 1.0) 3 (3) (weight: 1.0)
Adjacency list of 2 (2)
1 (1) (weight: -1.0)
Adjacency list of 3 (3)
1 (1) (weight: -1.0)
==================================================
Looking for a Node with member: 2
Adding 4 (4) as a child of 2 (2)
Adding an edge between 2 (2) and 4 (4) with weight 1.0
Adding nodewise edge from 2 (2) to 4 (4) with weight 1.0
Adjacent nodes of 2 (2)
1 (1) (weight: -1.0) 4 (4) (weight: 1.0)
Adding nodewise edge from 4 (4) to 2 (2) with weight -1.0
Adjacent nodes of 4 (4)
2 (2) (weight: -1.0)
==================================================
Adjacency list of 1 (1)
2 (2) (weight: 1.0) 3 (3) (weight: 1.0)
Adjacency list of 2 (2)
1 (1) (weight: -1.0) 4 (4) (weight: 1.0)
Adjacency list of 3 (3)
1 (1) (weight: -1.0)
Adjacency list of 4 (4)
2 (2) (weight: -1.0)
==================================================