Skip to content

Latest commit

 

History

History
68 lines (46 loc) · 2.8 KB

96df.md

File metadata and controls

68 lines (46 loc) · 2.8 KB

Back to questions

Solution to 96df: Tree nodes

See code at solutions/code/tutorialquestions/question96df

In my solution I define a TreeNode interface specifying the methods that all tree nodes should support:

TreeNode.java

I then define an abstract class, AbstractTreeNode, that implements this interface and specifies data and behaviour that should be the same for all tree nodes:

public abstract class AbstractTreeNode<E> implements TreeNode<E> {

  private E key;
  
  @Override
  public final E getKey() {
    return key;
  }
  
  @Override
  public final void setKey(E key) {
    this.key = key;
  }
}

Notice that here I have made the getKey and setKey methods final: Abstract``TreeNode defines these methods once and for all.

I have not specified in this class how a node's children should be represented, nor have I provided implementations for getNumberOfChildren, getChild or setChild, which are required by the TreeNode interface. These methods are implicitly declared abstract in AbstractTreeNode.

Class BinaryTreeNode extends AbstractTreeNode to define the behaviour of a tree node that has two children. The class declares two fields, one for each child:

private TreeNode<E> firstChild;
private TreeNode<E> secondChild;

In addition, the BinaryTreeNode class implements the getChild, setChild and getNumberOfChildren methods. The implementations of these methods are straightforward. For example, getNumberOfChildren simply returns the integer 2.

LeafNode is a similarly simple class to represent nodes that have no children. Notice that the getChild and setChild methods of this class use assert false to cause execution to abort if they are called.

Alternatively (and preferably) these methods could throw a runtime exception, e.g., an UnsupportedOperationException. This would be preferable because a) assertion checking only happens if -ea is specified as a JVM argument, and b) after throwing an exception there is no need for the method to return a value. This in getChild, we can simply write:

throw new UnsupportedOperationException();

instead of the less elegant:

assert false; return null;.

Nodes that are not binary or leaf nodes are represented by the class Arbitrary``TreeNode, which extends AbstractTreeNode and provides the node representation and operations as shown in the original TreeNode class.

Extension: See the sample solution for an implementation of toString() in AbstractTreeNode. This illustrates the power of abstract classes: we can write an algorithm to turn an arbitrary tree node into a string, even though the (direct and indirect) children of the tree node may have different runtime types.