Tree Node : Tree « Collections Data Structure « Java

Home
Java
1.2D Graphics GUI
2.3D
3.Advanced Graphics
4.Ant
5.Apache Common
6.Chart
7.Class
8.Collections Data Structure
9.Data Type
10.Database SQL JDBC
11.Design Pattern
12.Development Class
13.EJB3
14.Email
15.Event
16.File Input Output
17.Game
18.Generics
19.GWT
20.Hibernate
21.I18N
22.J2EE
23.J2ME
24.JavaFX
25.JDK 6
26.JDK 7
27.JNDI LDAP
28.JPA
29.JSP
30.JSTL
31.Language Basics
32.Network Protocol
33.PDF RTF
34.Reflection
35.Regular Expressions
36.Scripting
37.Security
38.Servlets
39.Spring
40.Swing Components
41.Swing JFC
42.SWT JFace Eclipse
43.Threads
44.Tiny Application
45.Velocity
46.Web Services SOA
47.XML
Java » Collections Data Structure » Tree 




Tree Node
      

//package org.j4me.collections;

/**
 * <code>TreeNode</code> objects can be combined into a tree.  The tree is not
 * a special tree such as a balanced tree.  It can have any number of levels
 * and each node can have any number of children.
 * <p>
 * Each tree node may have at most one parent and 0 or more children.
 * <code>TreeNode</code> provides operations for examining and modifying a node's
 * parent and children.  A node's tree is the set of all nodes that can be
 * reached by starting at the node and following all the possible links to
 * parents and children.  A node with no parent is the root of its tree; a
 * node with no children is a leaf.  A tree may consist of many subtrees,
 * each node acting as the root for its own subtree.
 * <p>
 * Every <code>TreeNode</code> can hold a reference to one user object.  It is up
 * to the developer to decide what the object is and how to use it.  For
 * example in maintaining the golf course tree the user object is an
 * <code>ICourseElement</code>.
 * <p>
 * <i>This is not a thread safe class.</i>  If used from multiple threads it
 * must be manually sychronized by your code.
 */
public class TreeNode
{
  /**
   * This node's parent node.  If this is the root of the tree then
   * the parent will be <code>null</code>.
   */
  private TreeNode parent;
  
  /**
   * An array of all this node's child nodes.  The array will always
   * exist (i.e. never <code>null</code>) and be of length zero if this is
   * a leaf node.
   * <p>
   * This is an array instead of a <code>Vector</code> to favor speed of
   * accessing the children.  The array takes longer on adds because
   * of array copying and management.  However to get the array it
   * can just be returned instead of creating a new array from the
   * <code>Vector</code> each time.  The tree is used frequently enough for
   * reading course elements that this difference makes a small impact
   * on rendering.
   */
  private TreeNode[] children = new TreeNode[0];
  
  /**
   * Constructs a tree node object.  It can become the root of a tree.
   * Or it can become a child of another node by calling the other node's
   * <code>add</code> method.
   * <p>
   * There is no user object attached to the node.  Call <code>setUserObject</code>
   * to attach one.
   */
  public TreeNode ()
  {
    // Nothing needed.
  }
  
  /**
   * Constructs a tree node object.  It can become the root of a tree.
   * Or it can become a child of another node by calling the other node's
   * <code>add</code> method.
   
   @param userObject is an object this node encapsulates.  It is up to
   *  the developer to maintain its type.  To get the object back out
   *  call <code>getUserObject</code>.
   */
  public TreeNode (Object userObject)
  {
    m_userData = userObject;
  }

  /**
   * Adds the <code>child</code> node to this container making this its parent.
   
   @param child is the node to add to the tree as a child of <code>this</code>
   
   @param index is the position within the children list to add the
   *  child.  It must be between 0 (the first child) and the
   *  total number of current children (the last child).  If it is
   *  negative the child will become the last child.
   */
  public void add (TreeNode child, int index)
  {
    // Add the child to the list of children.
    if index < || index == children.length )  // then append
    {
      TreeNode[] newChildren = new TreeNodechildren.length + ];
      System.arraycopychildren, 0, newChildren, 0, children.length );
      newChildren[children.length= child;
      children = newChildren;
    }
    else if index > children.length )
    {
      throw new IllegalArgumentException("Cannot add child to index " + index + ".  There are only " + children.length + " children.");
    }
    else  // insert
    {
      TreeNode[] newChildren = new TreeNodechildren.length + ];
      if index > )
      {
        System.arraycopychildren, 0, newChildren, 0, index );
      }
      newChildren[index= child;
      System.arraycopychildren, index, newChildren, index + 1, children.length - index );
      children = newChildren;
    }
    
    // Set the parent of the child.
    child.parent = this;
  }
  
  /**
   * Adds the <code>child</code> node to this container making this its parent.
   * The child is appended to the list of children as the last child.
   */
  public void add (TreeNode child)
  {
    addchild, -);
  }
  
  /**
   * Removes the child at position <code>index</code> from the tree.
   
   @param index is the position of the child.  It should be between
   *  0 (the first child) and the total number of children minus 1
   *  (the last child).
   @return The removed child node.  This will be <code>null</code> if
   *  no child exists at the specified <code>index</code>.
   */
  public TreeNode remove (int index)
  {
    if index < || index >= children.length throw new IllegalArgumentException("Cannot remove element with index " + index + " when there are " + children.length + " elements.");
    
    // Get a handle to the node being removed.
    TreeNode node = children[index];
    node.parent = null;
    
    // Remove the child from this node.
    TreeNode[] newChildren = new TreeNodechildren.length - ];
    if index > )
    {
      System.arraycopychildren, 0, newChildren, 0, index );
    }
    if index != children.length - )
    {
      System.arraycopychildren, index + 1, newChildren, index, children.length - index - );
    }
    children = newChildren;
    
    return node;
  }
  
  /**
   * Removes this node from its parent.  This node becomes the root
   * of a subtree where all of its children become first level
   * nodes.
   * <p>
   * Calling this on the root node has no effect.
   */
  public void removeFromParent ()
  {
    if parent != null )
    {
      int position = this.index();
      parent.removeposition );
      parent = null;
    }
  }

  /**
   * Gets the parent node of this one.
   
   @return The parent of this node.  This will return <code>null</code>
   *  if this node is the root node in the tree.
   */
  public TreeNode getParent ()
  {
    return parent;
  }
  
  /**
   * Returns if this node is the root node in the tree or not.
   
   @return <code>true</code> if this node is the root of the tree;
   *  <code>false</code> if it has a parent.
   */
  public boolean isRoot ()
  {
    if parent == null )
    {
      return true;
    }
    else
    {
      return false;
    }
  }

  /**
   * Gets a list of all the child nodes of this node.
   
   @return An array of all the child nodes.  The array will
   *  be the size of the number of children.  A leaf node
   *  will return an empty array, not <code>null</code>.
   */
  public TreeNode[] children ()
  {
    return children;
  }
  
  /**
   * Returns if this node has children or if it is a leaf
   * node.
   
   @return <code>true</code> if this node has children; <code>false</code>
   *  if it does not have any children.
   */
  public boolean hasChildren ()
  {
    if children.length == )
    {
      return false;
    }
    else
    {
      return true;
    }
  }
  
  /**
   * Gets the position of this node in the list of siblings
   * managed by the parent node.  This node can be obtained
   * by <code>this = parent.children[this.index()]</code>.
   
   @return The index of the child array of this node's
   *  parent.  If this is the root node it will return -1.
   */
  public int index ()
  {
    if parent != null )
    {
      for int i = 0; ; i++ )
      {
        Object node = parent.children[i];
        
        if this == node )
        {
          return i;
        }
      }
    }

    // Only ever make it here if this is the root node.
    return -1;
  }

  /**
   * Gets this node's depth in the tree.  The root node will
   * have a depth of 0, first-level nodes will have a depth
   * of 1, and so on.
   
   @return The depth of this node in the tree.
   */
  public int depth ()
  {
    int depth = recurseDepthparent, );
    return depth;
  }

  /**
   * Recursive helper method to calculate the depth of a node.
   * The caller should pass its parent and an initial depth of 0.
   * <p>
   * A recursive approach is used so that when a node that is
   * part of a tree is removed from that tree, we do not need
   * to recalculate the depth of every node in that subtree.
   
   @param node is the node to recursively check for its depth.
   *  This should be set to <code>parent</code> by the caller.
   @param depth is the depth of the current node (i.e. the
   *  child of <code>node</code>).  This should be set to 0 by the
   *  caller.
   */
  private int recurseDepth (TreeNode node, int depth)
  {
    if node == null )  // reached top of tree
    {
      return depth;
    }
    else
    {
      return recurseDepthnode.parent, depth + );
    }
  }

  /**
   * A handle to the programmer assigned object encapsulated by this
   * node.  This will be <code>null</code> when the user has not assigned
   * any data to this node.
   */
  private Object m_userData;
  
  /**
   * Attaches a user defined object to this node.  Only one
   * object can be attached to a node.
   
   @param userObject is the programmer defined object to
   *  attach to this node in the tree.  Set it to <code>null</code>
   *  to clear any objects.
   */
  public void setUserObject (Object userObject)
  {
    m_userData = userObject;
  }
  
  /**
   * Gets the user defined object attached to this node.  It
   * must be cast back to what it was inserted as.  It is up
   * to the developer to make this cast.
   
   @return The programmer defined object attached to this
   *  node in the tree.  Returns <code>null</code> if no object is
   *  attached.
   */
  public Object getUserObject ()
  {
    return m_userData;
  }
}
--------
package org.j4me.collections;

import j2meunit.framework.*;

/**
 * Tests the <code>TreeNode</code> object.  It is a generic tree (integer.e. not a balanced tree
 * or some other specialized tree).
 
 @see org.j4me.collections.TreeNode
 */
public class TreeNodeTest
  extends TestCase
{
  public TreeNodeTest ()
  {
    super();
  }
  
  public TreeNodeTest (String name, TestMethod method)
  {
    supername, method );
  }
  
  public Test suite ()
  {
    TestSuite suite = new TestSuite();
    
    suite.addTest(new TreeNodeTest("testIllegalOperations"new TestMethod() 
        public void run(TestCase tc) {((TreeNodeTesttc).testIllegalOperations()} }));
    suite.addTest(new TreeNodeTest("testUserObjects"new TestMethod() 
        public void run(TestCase tc) {((TreeNodeTesttc).testUserObjects()} }));
    suite.addTest(new TreeNodeTest("testRoot"new TestMethod() 
        public void run(TestCase tc) {((TreeNodeTesttc).testRoot()} }));
    suite.addTest(new TreeNodeTest("testOneChild"new TestMethod() 
        public void run(TestCase tc) {((TreeNodeTesttc).testOneChild()} }));
    suite.addTest(new TreeNodeTest("testMultipleChildren"new TestMethod() 
        public void run(TestCase tc) {((TreeNodeTesttc).testMultipleChildren()} }));
    suite.addTest(new TreeNodeTest("testMultipleLevels"new TestMethod() 
        public void run(TestCase tc) {((TreeNodeTesttc).testMultipleLevels()} }));
    suite.addTest(new TreeNodeTest("testBigTree"new TestMethod() 
        public void run(TestCase tc) {((TreeNodeTesttc).testBigTree()} }));
    
    return suite;
  }
  
  /**
   * Tests the tree nodes defend themselves again invalid parameters that would
   * be the result of programming errors.
   */
  public void testIllegalOperations ()
  {
    // Test cannot add a child node to position greater than available number of children.
    boolean caughtException = false;
    
    try
    {
      TreeNode root = new TreeNode();
      root.addnew TreeNode());
    }
    catch (IllegalArgumentException e)
    {
      caughtException = true;
    }
    catch (Throwable t)
    {
      String actualExceptionName = t.getClass().getName();
      fail"Expected exception 'IllegalArgumentException' and got '" + actualExceptionName + "'." );
    }
    
    if caughtException == false )
    {
      fail"Expected exception 'IllegalArgumentException' but no exceptions caught." );
    }
    
    
    // Test remove a child node from position greater than available number of children.
    caughtException = false;
    
    try
    {
      TreeNode root = new TreeNode();
      root.remove);
    }
    catch (IllegalArgumentException e)
    {
      caughtException = true;
    }
    catch (Throwable t)
    {
      String actualExceptionName = t.getClass().getName();
      fail"Expected exception 'IllegalArgumentException' and got '" + actualExceptionName + "'." );
    }
    
    if caughtException == false )
    {
      fail"Expected exception 'IllegalArgumentException' but no exceptions caught." );
    }
  }
  
  /**
   * Tests that user objects can be attached and extracted from
   * a tree node.
   */
  public void testUserObjects ()
  {
    String user = "This is a test string.\n  It should go in and come out the same.";
    Integer user2 = new Integer(13);
    
    // Create a node with the user defined object.
    TreeNode node = new TreeNodeuser );
    
    // Get the object back out.
    Object obj = node.getUserObject();
    String result = (String)obj;
    assertEquals("The attached string should be the same one as put in.", user, result);
    
    // Try erasing the string.
    node.setUserObjectnull );
    obj = node.getUserObject();
    assertNull("No user object should be attached to the node.", obj);
    
    // Put a different object back in and pull it out.
    node.setUserObjectuser2 );
    obj = node.getUserObject();
    Integer intResult = (Integer)obj;
    assertEquals("The attached Integer should be the same one as put in.", user2, intResult);
  }
  
  /**
   * Tests assertions about a root node.  This is a very simple test
   * and should be right before working with children.
   */
  public void testRoot ()
  {
    TreeNode root = new TreeNode();
    
    // Verify properties of the root node.
    boolean isRoot = root.isRoot();
    assertTrue("The node should be the root node.", isRoot);
    
    int index = root.index();
    assertEquals("The root node should have an index of -1 since it has no parent.", -1, index);
    
    int depth = root.depth();
    assertEquals("The root node should have depth of 0 since it has no parent."0, depth);
    
    TreeNode parent = root.getParent();
    assertNull("The root node should not have a parent node.", parent);
    
    boolean hasChildren = root.hasChildren();
    assertTrue("The root node should not have any children because none have been added.", hasChildren == false);
    
    TreeNode[] children = root.children();
    int childLength = children.length;
    assertEquals("The root node should not have any children because none have been added."0, childLength);
    
    // Verify the following method doesn't throw an exception.
    root.removeFromParent();
  }
  
  /**
   * Test a tree that has a root and just one child.  This is a simple
   * test to verify the child has properties appropriately set before
   * testing more complex trees.
   */
  public void testOneChild ()
  {
    // Create the tree.
    TreeNode root = new TreeNode();
    TreeNode child = new TreeNode();
    root.addchild );
    
    // Verify properties of the child node.
    boolean isRoot = child.isRoot();
    assertTrue("The node should not be the root node.", isRoot == false);
    
    int index = child.index();
    assertEquals("The child node should have an index of 0 since it is the only child."0, index);
    
    int depth = child.depth();
    assertEquals("The child node should have depth of 1 since it is a first level node."1, depth);
    
    TreeNode parent = child.getParent();
    assertEquals("The child's parent should be the root node.", root, parent);
    
    boolean hasChildren = child.hasChildren();
    assertTrue("The child node should not have any children because none have been added.", hasChildren == false);
    
    hasChildren = root.hasChildren();
    assertTrue("The root node should now have children.", hasChildren == true);
    
    TreeNode[] children = child.children();
    int childLength = children.length;
    assertEquals("The child node should not have any children because none have been added."0, childLength);
    
    children = root.children();
    childLength = children.length;
    assertEquals("The root node should have 1 child."1, childLength);

    TreeNode theChild = children[0];
    assertEquals("The root's child should be child.", child, theChild);
    
    // Now remove the child from the root.
    child.removeFromParent();
    
    isRoot = child.isRoot();
    assertTrue("The child node should now be the root of its own subtree.", isRoot == true);
    
    depth = child.depth();
    assertEquals("The child node should have depth of 0 since it is now the root."0, depth);
    
    parent = child.getParent();
    assertEquals("The child should not have a parent since it is now the root.", null, parent);
    
    hasChildren = root.hasChildren();
    assertTrue("The root node should no longer have any children.", hasChildren == false);
  }

  /**
   * This tests a tree only 1 level deep, but there are several first
   * level children.  This is useful to test that siblings are kept
   * correctly before testing multiple level trees.
   */
  public void testMultipleChildren ()
  {
    TreeNode root = new TreeNode();
    TreeNode child1 = new TreeNode();
    TreeNode child2 = new TreeNode();
    TreeNode child3 = new TreeNode();
    
    // Add the children.
    root.addchild1, );
    root.addchild3, );  // Add with index, but really appending child
    root.addchild2, );  // Add out of order to test insertion in the middle of the children
    
    TreeNode[] children = root.children();
    assertEquals("child1 should be the first child.", child1, children[0]);
    assertEquals("child2 should be the second child.", child2, children[1]);
    assertEquals("child3 should be the third child.", child3, children[2]);
    
    // Verify the properties of the children.
    for int i = 0; i < children.length; i++ )
    {
      TreeNode child = children[i];
      
      int index = child.index();
      assertEquals("child" (i+1" should have an index of " + i, i, index);
      
      boolean isRoot = child.isRoot();
      assertTrue("child" (i+1" should not be the root node.", isRoot == false);
      
      int depth = child.depth();
      assertEquals("child" (i+1" should have depth of 1 since it is a first level node."1, depth);
      
      TreeNode parent = child.getParent();
      assertEquals("child" (i+1"'s parent should be the root node.", root, parent);
      
      boolean hasChildren = child.hasChildren();
      assertTrue("child" (i+1" should not have any children because none have been added.", hasChildren == false);
    }
    
    // Remove the middle child.
    TreeNode removed = root.remove);
    assertEquals("The removed node should be child2.", child2, removed);
    assertEquals("child2 should now have a depth of 0."0, removed.depth());
    
    children = root.children();
    assertEquals("The root should now have 2 children."2, children.length);
    assertEquals("child3 should be the second child.", child3, children[1]);
    
    // Add the middle child back in.
    root.addremoved, );
    children = root.children();
    TreeNode node = children[1];

    assertEquals("The second node should be child2 again.", child2, node);
    assertEquals("child2's parent should be the root again.", root, child2.getParent());
    assertEquals("child2's depth should be 1 again."1, child2.depth());
    
    // Remove all the children.
    root.remove);
    root.remove);
    child1.removeFromParent();
    assertTrue("The root should not have any children now.", root.hasChildren() == false);
  }
  
  /**
   * This tests that multiple levels of the tree work correctly.  Each
   * level has only 1 child.  This is a simple test to verify depth
   * works before moving onto more complex trees.
   */
  public void testMultipleLevels ()
  {
    TreeNode root = new TreeNode();
    TreeNode depth1 = new TreeNode();
    TreeNode depth2 = new TreeNode();
    TreeNode depth3 = new TreeNode();
    
    // Add the children.
    root.adddepth1 );
    depth2.adddepth3 );
    depth1.adddepth2 );

    // Verify the properties of the nodes.
    assertTrue("The root should have 1 child.", root.hasChildren() == true);
    assertEquals("The root should have a depth of 0."0, root.depth());
    assertEquals("The root should not have a parent.", null, root.getParent());
    
    assertTrue("depth1 should have 1 child.", depth1.hasChildren() == true);
    assertEquals("depth1 should have a depth of 1."1, depth1.depth());
    assertEquals("depth1 should have root as its parent.", root, depth1.getParent());
    
    assertTrue("depth2 should have 1 child.", depth2.hasChildren() == true);
    assertEquals("depth2 should have a depth of 2."2, depth2.depth());
    assertEquals("depth2 should have depth1 as its parent.", depth1, depth2.getParent());
    
    assertTrue("depth3 should have not have any children.", depth3.hasChildren() == false);
    assertEquals("depth3 should have a depth of 3."3, depth3.depth());
    assertEquals("depth3 should have depth2 as its parent.", depth2, depth3.getParent());
    
    // Cut the tree in 1/2.
    depth2.removeFromParent();
    assertTrue("depth2 should now be a root.", depth2.isRoot() == true);
    assertEquals("depth2 should now have a depth of 0."0, depth2.depth());
    assertEquals("depth3 should now have a depth of 1."1, depth3.depth());
    assertTrue("depth1 should not have any children now.", depth1.hasChildren() == false);
  }
  
  /**
   * This tests a tree with multiple varying depths and multiple
   * varying amounts of children at each depth.
   */
  public void testBigTree ()
  {
    String testData = "";
    
    TreeNode root = new TreeNode();
    TreeNode d1c0 = new TreeNodetestData );
    TreeNode d1c1 = new TreeNodetestData );
    TreeNode d1c2 = new TreeNodetestData );
    TreeNode d2c1c0 = new TreeNodetestData );
    TreeNode d2c1c1 = new TreeNodetestData );
    TreeNode d2c1c2 = new TreeNodetestData );
    TreeNode d2c2c0 = new TreeNodetestData );
    TreeNode d2c2c1 = new TreeNodetestData );
    TreeNode d3c2c0c0 = new TreeNodetestData );
    TreeNode d3c2c0c1 = new TreeNodetestData );
    
    root.addd1c0 );
    root.addd1c1 );
    root.addd1c2 );
    
    d1c1.addd2c1c1 );  // Second child
    d1c1.addd2c1c0, );  // First child
    d1c1.addd2c1c2 );  // Third child
    
    d1c2.addd2c2c0 )
    d2c2c0.addd3c2c0c0 );
    d2c2c0.addd3c2c0c1 );

    d1c2.addd2c2c1 )
    
    // Verify the tree structure.
    assertEquals("root should be the parent of d1c0", root, d1c0.getParent());
    assertEquals("root should be the parent of d1c1", root, d1c1.getParent());
    assertEquals("root should be the parent of d1c2", root, d1c2.getParent());
    
    assertEquals("d1c1 should be the parent of d2c1c0", d1c1, d2c1c0.getParent());
    assertEquals("d1c1 should be the parent of d2c1c1", d1c1, d2c1c1.getParent());
    assertEquals("d1c1 should be the parent of d2c1c2", d1c1, d2c1c2.getParent());
    
    assertEquals("d1c2 should be the parent of d2c2c0", d1c2, d2c2c0.getParent());
    assertEquals("d1c2 should be the parent of d2c2c1", d1c2, d2c2c1.getParent());
    
    assertEquals("d2c2c0 should be the parent of d3c2c0c0", d2c2c0, d3c2c0c0.getParent());
    assertEquals("d2c2c0 should be the parent of d3c2c0c1", d2c2c0, d3c2c0c1.getParent());
    
    // Verify the depths of some of the nodes.
    assertEquals("root should have a depth of 0"0, root.depth());
    assertEquals("d1c1 should have a depth of 1"1, d1c1.depth());
    assertEquals("d2c2c0 should have a depth of 2"2, d2c2c0.depth());
    assertEquals("d3c2c0c1 should have a depth of 3"3, d3c2c0c1.depth());
    
    // Verify we can traverse the tree from root to d3c2c0c0.
    TreeNode node = root.children()[2];  // d1c2
    node = node.children()[0];  // d2c2c0
    node = node.children()[0];  // d3c2c0c0
    assertEquals("We should have tranversed the tree to d3c2c0c0.", d3c2c0c0, node);
    
    assertEquals("Should have test data as user object from node d3c2c0c0.", testData, node.getUserObject());
  }
}

   
    
    
    
    
    
  














Related examples in the same category
1.Binary TreeBinary Tree
2.Your own tree with generic user object
3.Tree Node for the for a general tree of Objects
4.A tree structure that maps inheritance hierarchies of classesA tree structure that maps inheritance hierarchies of classes
5.Data structure that mantains data in a ordered binary tree; each node is greater (smaller) or equal than its 2 sub-nodes, for all the hierarchy.Data structure that mantains data in a ordered binary tree; each node is greater (smaller) or equal than its 2 sub-nodes, for all the hierarchy.
6.Ternary Search Tree
7.Char Prefix Tree
8.Lightweight tree n-arity structure
9.This class is designed to provide a generic tree that allows duplicates.
10.Useful for string set lookups and command completion stuff
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.