University-of-Washington-Navigator / src / main / java / graph / Node.java
Node.java
Raw
package graph;
import java.util.*;

/**
 * Node is mutable and represents an object and the edges it has to other objects. Edges and
 * corresponding children cannot be null. See the Graph class for more details.
 */
public class Node<E, F> {
    private E name;
    private Map<F, List<Node<E, F>>> edges;
    public static final boolean DEBUGGING = false;

    // Abstraction Function:
    // Node represents an object that has edges to and from other objects in the way that
    // each object "points" at another one. These edges have labels, given by the String keys
    // in edges. These labels are mapped to Nodes that have an incoming edge of label String.
    // Each Node has a name/data. If edges is empty, the Node has no connections to other
    // Nodes.
    //
    // Representation Invariant:
    // edges != null, name != null, !edges.containsKey(null),
    // !edges.containsValue(null)

    /**
     * Creates a new Node using the given data
     *
     * @param name the data of the Node being constructed
     * @spec.modifies this
     * @spec.effects Constructs a new Node with data name
     * @throws IllegalArgumentException if name is null
     */
    public Node(E name) {
        if (name == null) {
            throw new IllegalArgumentException();
        }
        this.name = name;
        edges = new HashMap<F, List<Node<E, F>>>();
        checkRep();
    }

    /**
     * Returns this Node's data
     *
     * @return This Node's data
     */
    public E getName() {
        checkRep();
        return name;
    }

    /**
     * Returns a map of the edge labels and corresponding child Nodes
     *
     * @return A Map of names of edges branching from this and their corresponding child Nodes
     */
    public Map<F, List<Node<E, F>>> getEdges() {
        checkRep();
        return edges;
    }

    /**
     * Returns an ordered set of edges from parent to child.
     *
     * @param child The desired edges' connected child node from this node
     * @spec.requires There must be an edge from this node to the child node
     * @return All edges from the parent to the child
     */
    public List<F> getEdgesTo(E child) {
        List<F> list = new ArrayList<F>();
        Node<E, F> childNode = new Node<E, F>(child);
        for (F edge : edges.keySet()) {
            if (edges.get(edge).contains(childNode)) {
                list.add(edge);
            }
        }
        return list;
    }

    /**
     * Returns true if this and other are equal (two Nodes are equal if they have the
     * same data)
     *
     * @param other Checked if it is equal to this Node
     * @return True if this and other are equal, but false if not
     */
    @Override
    public boolean equals(Object other) {
        if (!(other instanceof Node<?, ?>)) {
            return false;
        }
        Node<?, ?> node2 = (Node<?, ?>) other;
        return this.name.equals(node2.getName());
    }

    /**
     * Returns this Node's hashCode
     *
     * @return This Node's hashCode
     */
    @Override
    public int hashCode() {
        return this.name.hashCode();
    }

    /**
     * Returns a String representation of this node
     *
     * @return String representing this node
     */
    @Override
    public String toString() {
        return name.toString();
    }

    /**
     * Throws an exception if the representation invariant is violated.
     */
    private void checkRep() {
        assert name != null;
        assert edges != null;
        if (DEBUGGING) {
            if (!edges.isEmpty()) {
                // containsKey and containsValue threw NullPointerExceptions when checked for
                // null so I looped through everything one-by-one
                for (F label : edges.keySet()) {
                    assert label != null;
                    for (Node<E, F> n : edges.get(label)) {
                        assert n != null;
                    }
                }
            }
        }
    }
}