/* An instance of this class represents on outdegree-1 directed graph. ** Such a graph is one in which every node has exactly one edge emanating ** from it. In a graph having N nodes, they are identified by the integers ** in the range [0..N). ** ** In an outdegree-1 graph, for each node v and each natural number k, ** there is a unique path starting at v and having length k. Let ** destination(v,k) be the node at which that path ends. (In particular, ** destination(v,1) is the node at the end of the edge emanating from v.) ** ** Author: R. McCloskey ** Date: October 2022 */ public class OutDeg1Graph { // instance variables // ------------------ protected int[] edges; // edges[u] = v means u's outgoing edge goes to v protected int opCntr; // a measure of how much work this object has done // since the last call to resetWorkMeasure(). // constructor // ----------- /* Initializes this outdegree-1 graph to be that described by the given ** array, arcs[]. The meaning of arcs[v] = w is that the outgoing edge ** from node v goes to node w. ** An IllegalArgumentException is thrown in the case that arcs[] fails to ** satisfy 0 <= arcs[i] < arcs.length for all i. */ public OutDeg1Graph(int[] arcs) { // Verify that arcs[] is a valid description of an outdegree-1 graph. final int N = arcs.length; for (int i = 0; i != N; i++) { if (arcs[i] < 0 || arcs[i] >= N) { throw new IllegalArgumentException("Edge goes to nonexistent node"); } } // Make the instance variable refer to a clone of arcs[] so that the // client program cannot, in effect, modify the graph. edges = arcs.clone(); resetWorkMeasure(); } // observers // --------- /* Returns the number of nodes in this graph. */ public int numNodes() { return edges.length; } /* Returns the ID of the node to which node v's outgoing edge goes. */ public int next(int v) { opCntr++; return edges[v]; } /* Returns the node reached by the path starting at node v ** and having the specified length. ** pre: length >= 0 */ public int destination(int v, int length) { for (int i=0; i != length; i++) { v = next(v); } return v; } /* Returns a measure of how much work/computation this object has ** performed since the last time that measure was reset (via a ** call to the resetWorkMeasure() method). */ public int workMeasure() { return opCntr; } /* Returns a string that reports the number of nodes in this graph ** and shows a list of its edges. */ @Override public String toString() { StringBuilder s = new StringBuilder(); final int N = numNodes(); s.append("# nodes: " + N); s.append("\nedges: "); for (int i=0; i != N; i++) { s.append("(" + i + ',' + next(i) + ") "); } return s.toString(); } // mutator // ------- /* Resets the work measure to zero. */ public void resetWorkMeasure() { opCntr = 0; } }