CMPS 144L
Lab Activity: Family Trees

The relevant files are these:

An instance of the FamilyForest class represents a forest of family trees. (A forest is just a collection of trees.) Among its methods, two are stubbed (namely, rootOf() and nearestCommonAncestor()) and are waiting for you to complete them.

The manner in which trees are represented by instances of this class reflects the fact that it is intended for use by applications (such as Cousins) in which the tree nodes are traversed in a child-to-parent direction (rather than the perhaps more common parent-to-child direction). Specifically, the only piece of data that is associated to a node is the identity of its parent. Indeed, a forest of trees is represented by a single instance variable, parent[], of type int[], where the condition i == parent[j] means that node i is the parent of node j. (As you can infer from the last statement, nodes in the forest are identified by natural numbers.)

The Cousins class is a Java application that constructs a family forest on the basis of the data in a file whose name is provided to it in a command-line argument (or, as jGrasp calls it, a run argument). Then it waits for the user to "ask" it to reveal the relationship between two specified nodes in the family forest. The method that reports that relationship, reportRelationship()), is left for you to complete. Of course, the point is that that method will need to make use of methods in the FamilyForest class.

The contents of the input.txt file describes the family forest (which has two trees) shown in the left half of the figure below. In the right half is a sample interaction between a user and the Cousins application, which was given the input.txt file as input:

         0                       17
         |                      /  \
         |                     /    \
         1                    18     19
        /|\                  /  \     |
       / | \                /    \    |
      /  |  \             20     21  22
     /   |   \
    /    |    \
   2     3     4
  /     /|      \
 /     / |       \
5     7  8        11
|       / \      / |\
|      /   \    /  | \
6     9    10  12 13  14
                  / \
                 /   \
                15   16
Enter pair of node IDs: 12 4
2-descendant

Enter pair of node IDs: 1 15
4-ancestor

Enter pair of node IDs: 2 16
0-cousins 3 times removed

Enter pair of node IDs: 9 15
2-cousins 1 times removed

Enter pair of node IDs: 7 19
Unrelated

Enter pair of node IDs: 18 18
0-ancestor

Enter pair of node IDs: -1 5
Goodbye.

The relationship (or lack thereof) between two nodes A and B falls into one of four categories:

  1. A and B are unrelated iff they have no common ancestor, which is to say that they lie in distinct trees of the family forest.
  2. A is the k-ancestor of B iff the path of length k from B towards the root of its tree lands at A. For example, if A is B's grandparent, then A is the 2-ancestor of B. If A and B are the same node, A is the 0-ancestor of B.
  3. A is a k-descendant of B iff B is the k-ancestor of A (which is to say that the path of length k from A towards the root of its tree lands at B).
  4. A and B are k-th cousins r times removed iff the nearest common ancestor of A and B, call it C, is neither A nor B, and

    where dist(x,y) is the length of the path from x to y (i.e., the number of edges in that path).