Title: Computer Science 187
1Computer Science 187
Introduction to Programming with Data Structures
Lecture 17 Implementing Trees
Announcements
- Current OWL and project 4 are due today (November
8). - New programming project up soon.
- New OWL up soon.
2General Tree Interfaces
- Interface for traversals of general trees
public interface TreeInterface public Object
getData() public int getHeight() public int
getNumberOfNodes() public boolean
isEmpty() public void clear()
public interface TreeIteratorInterface public
Iterator PreorderIterator() public Iterator
PostOrderIterator() public Iterator
InorderIterator() public Iterator
LevelOrderIterator()
3Binary Tree interfacemethods only
public Object getData() public int
getHeight() public int getNumberOfNodes() public
boolean isEmpty() public void clear() public
void setTree(Object rootData) public void
setTree(Object rootData, BinaryTreeInterface
leftTree, BinaryTreeInterface
rightTree) public Iterator PreorderIterator() pu
blic Iterator PostOrderIterator() public
Iterator InorderIterator() public Iterator
LevelOrderIterator()
from TreeInterface
from TreeIteratorInterface
4The Binary Tree Interface
- public interface BinaryTreeInterface extends
- TreeInterface, TreeIteratorInterface
-
- public void setTree(Object rootData)
- public void setTree(Object rootData,
BinaryTreeInterface - leftTree, BinaryTreeInterface
rightTree) - //end BinaryTreeInterface
Exceptions?
5and recall our Binary Tree Node Interface
- public interface BinaryNodeInterface
-
- public Object getData() //returns the data
element at this node. - public void setData(Object myElement) //sets
data element to myElement - public void setLeftChild(BinaryNodeInterface
myLeft) //set left child to myLeft - public void setRightChild(BinaryNodeInterface
myRight) //set right child to myRight - public BinaryNodeInterface getLeftChild() //ret
urns left child node - public BinaryNodeInterface getRightChild()
//returns right child node - public boolean hasLeftChild() //returns true
if this node has a left child - public boolean hasRightChild() //returns true
if this node has a right child - public boolean isLeaf() //returns true if
node is a leaf node.
6The methods of the interfaces
BinaryTreeInterface
BinaryNodeInterface
public Object getData() public int
getHeight() public int getNumberOfNodes() public
boolean isEmpty() public void clear() public
void setTree(Object rootData) public void
setTree(Object rootData,
BinaryTreeInterface leftTree,
BinaryTreeInterface rightTree) public Iterator
PreorderIterator() public Iterator
PostOrderIterator() public Iterator
InorderIterator() public Iterator
LevelOrderIterator()
public Object getData() public void
setData(Object myElement) public void
setLeftChild(BinaryNodeInterface myLeft) public
void setRightChild(BinaryNodeInterface
myRight) public BinaryNodeInterface
getLeftChild() public BinaryNodeInterface
getRightChild() public boolean hasLeftChild()
public boolean hasRightChild() public boolean
isLeaf()
7An Example Program
- public class BinaryTreeTest
-
- public static void main (String args) throws
BinaryTreeException -
- BinaryTree t new BinaryTree(new Integer(1))
- System.out.println("Element at root of tree
- "
t.getData()) - System.out.println(Tree t is ")
- t.inorderTraverse()
- System.out.println()
-
- BinaryTree tree1 new BinaryTree()
- tree1.setTree(new Integer(2),
- new BinaryTree(new
Integer (4)), - new BinaryTree(new
Integer (5))) - System.out.println("Tree1 is ")
- tree1.inorderTraverse()
- System.out.println()
-
8Example, cont'd.
- BinaryTree tree2 new BinaryTree()
- tree2.setTree(new Integer (6),
- new BinaryTree(new Integer(7)),
- new BinaryTree(new
Integer(8))) - System.out.println("tree2 is ")
- tree2.inorderTraverse()
- System.out.println()
-
- BinaryTree tree3 new BinaryTree()
- tree3.setTree(new Integer(3), tree2, null)
- System.out.println("Tree3 is ")
- tree3.inorderTraverse()
- System.out.println()
-
- BinaryTree tree4new BinaryTree()
- tree4.setTree(new Integer (1), tree1, tree3)
- System.out.println("Final tree is ")
- tree4.inorderTraverse()
- System.out.println()
1
tree4
9Using attach
//tree4.setTree(new Integer (1), tree1,
tree3) BinaryTree tree4new BinaryTree(new
Integer(1)) tree4.attachLeft(tree1) tree4.attach
Right(tree3) System.out.println("Final tree is
") tree4.inorderTraverse() System.out.println()
10Something to keep in mind
- BinaryNode N tree3.getRoot()
- N.setData(new Integer(1000))
- System.out.println("Tree4 after changing
- the data in the root node of
tree3") - tree4.inorderTraverse()
- System.out.println()
Whats the output?
11Traversing a tree
- Suppose I wanted to visit all the nodes in this
tree. - Furthermore, suppose I wanted to perform some
operation on the data there (such as printing it
out).
- What are some of the possible visitation patterns
we could use?
12Tree Traversal Patterns
- A Possible Pattern
- Touch Root Node
- Visit Left subtree
- Visit Right subtree
- Must be applied at all levels of the tree.
1
2
9
3
6
10
11
4
5
7
8
12
- Called a PreOrder Traversal
touch means doing something at the node, such
as printing the element there.
13preorderTraverse( )
- public void preorderTraverse()
- preorderTraverse(root)
- private void preorderTraverse(BinaryNode node)
-
- if (node ! null)
-
- System.out.print(node.getData()" ")
- preorderTraverse((BinaryNode)node.getLeftChil
d()) - preorderTraverse((BinaryNode)node.getRightChi
ld()) -
Note the casts..
Print tree using preorder traversal 1 2 4 5
3 6 7 8
14Tree Traversal Patterns
- A Possible Pattern
- Visit Left subtree
- Touch Root node
- Visit Right subtree
- Must be applied at all levels of the tree.
- Called an InOrder Traversal
15inorderTraverse()
- public void inorderTraverse()
- inorderTraverse(root)
- private void inorderTraverse(BinaryNode node)
-
- if (node ! null)
-
- inorderTraverse((BinaryNode)node.getLeftChild
()) - System.out.print(node.getData()" ")
- inorderTraverse((BinaryNode)node.getRightChil
d()) -
Print tree using inorder traversal 4 2 5 1 7
6 8 3
16Tree Traversal Patterns
- A Possible Pattern
- Visit Left subtree
- Visit Right subtree
- Touch Root Node
- Must be applied at all levels of the tree.
12
7
11
3
6
8
10
1
2
4
5
9
- Called a PostOrder Traversal
17postorderTraverse( )
- public void postorderTraverse()
- postorderTraverse(root)
- private void postorderTraverse(BinaryNode node)
-
- if (node ! null)
-
- postorderTraverse((BinaryNode)node.getLeftChi
ld()) - postorderTraverse((BinaryNode)node.getRightCh
ild()) - System.out.print(node.getData() )
-
Print tree using postorder traversal 4 5 2 7
8 6 3 1
18The BinaryNode Class
- public class BinaryNode implements
BinaryNodeInterface - private Object data
- private BinaryNode left
- private BinaryNode right
- //Constructors
- public BinaryNode()
- this(null)
-
- public BinaryNode(Object dataPortion)
- this(dataPortion, null,null)
-
- public BinaryNode(Object nodeData, BinaryNode
leftChild, - BinaryNode
rightChild) - data nodeData
- left leftChild
- right rightChild
19The BinaryNode Class
- public boolean isLeaf()
- return ((left null) (right null))
-
- public Object getData()
- return data
-
- public void setData(Object newData)
- datanewData
- public void setLeftChild(BinaryNodeInterface
leftChild) - left (BinaryNode) leftChild
- public BinaryNodeInterface getLeftChild()
- return left
20The BinaryNode Class
- public void setRightChild(BinaryNodeInterface
rightChild) - right (BinaryNode) rightChild
- public BinaryNodeInterface getRightChild()
- return right
- public boolean hasLeftChild()
- return left ! null
- public boolean hasRightChild()
- return right ! null
- //end Binary Node
21The BinaryTree Class
- import java.util.
- public class BinaryTree implements
BinaryTreeInterface, -
java.io.Serializable -
- //Implements a binary tree using the BinaryNode
class -
- protected BinaryNode root
22The BinaryTree ClassConstructors
//The Constructors public BinaryTree() root
null public BinaryTree(Object rootData)
root new BinaryNode(rootData, null,
null) public BinaryTree(Object rootData,
BinaryTree leftTree,
BinaryTree rightTree) privateSetTree(root
Data, leftTree, rightTree)
23The BinaryTree Class getRootData
public Object getRootData() Object rootData
null if (root ! null) rootDataroot.getData(
) return rootData
public Object getRootData() public int
getHeight() public int getNumberOfNodes() public
boolean isEmpty() public void clear() public
void setTree(Object rootData) public void
setTree(Object rootData, BinaryTreeInterface
leftTree, BinaryTreeInterface
rightTree) public Iterator getPreorderIterator()
public Iterator getPostOrderIterator() public
Iterator getInorderIterator() public Iterator
getLevelOrderIterator()
Null data at root or no root at
all? EXCEPTIONS????
24The getHeight() method
- getHeight() should be a tree method e.g.
T.getHeight() - getHeight() needs to have a
- node as an argument to
- support recursion
- Notice the structure
- getHeight() is a public
- tree method
- getHeight(node) is a private
- method that takes a node
- as an argument
- public int getHeight()
-
- return getHeight(root)
-
We should use this mechanism on MOST tree methods
that need a node argument.
25The BinaryTree Class getHeight
- Recall that the height of a tree is the same as
the depth of the deepest node in the tree. - The height of a tree rooted at a node is 1
max(height of left tree, height of right tree)
RECURSIVE
public int getHeight() return getHeight(root)
public Object getRootData() public int
getHeight() public int getNumberOfNodes() public
boolean isEmpty() public void clear() public
void setTree(Object rootData) public void
setTree(Object rootData,
BinaryTreeInterface leftTree,
BinaryTreeInterface rightTree) public Iterator
getPreorderIterator() public Iterator
getPostOrderIterator() public Iterator
getInorderIterator() public Iterator
getLevelOrderIterator()
26The BinaryTree Class getHeight
- private int getHeight(BinaryNode node)
- int height 0
- if (node ! null)
- height 1 Math.max (
- getHeight((BinaryNode)node.getLeftChild()),
- getHeight((BinaryNode)node.getRightChild()))
- return height
27The BinaryNode Class getNumberOfNodes
- Number of nodes in a tree is 1 number in left
tree number in right tree - Another naturally recursive method
public int getNumberOfNodes() return
getNumberOfNodes(root)
public Object getRootData() public int
getHeight() public int getNumberOfNodes() public
boolean isEmpty() public void clear() public
void setTree(Object rootData) public void
setTree(Object rootData,
BinaryTreeInterface leftTree,
BinaryTreeInterface rightTree) public Iterator
getPreorderIterator() public Iterator
getPostOrderIterator() public Iterator
getInorderIterator() public Iterator
getLevelOrderIterator()
28The BinaryTree Class getNumberOfNodes
private int getNumberOfNodes(BinaryNode node)
int leftNumber 0 int rightNumber 0 if
((BinaryNode)node.getLeftChild() !null)
leftNumbergetNumberOfNodes(
(BinaryNode)node.getLef
tChild()) if ((BinaryNode)node.getRightChild()
! null) rightNumbergetNumberOfNodes(
(BinaryNode)node.getRightChild()) return
1leftNumberrightNumber
29The BinaryTree Class isEmpty, clear
public boolean isEmpty() return
rootnull public void clear() root null
public Object getRootData() public int
getHeight() public int getNumberOfNodes() public
boolean isEmpty() public void clear() public
void setTree(Object rootData) public void
setTree(Object rootData,
BinaryTreeInterface leftTree,
BinaryTreeInterface rightTree) public Iterator
getPreorderIterator() public Iterator
getPostOrderIterator() public Iterator
getInorderIterator() public Iterator
getLevelOrderIterator()
30The BinaryTree ClasssetTree
- public void setTree(Object rootData)
- rootnew BinaryNode(rootData)
- public void setTree(Object rootData,
BinaryTreeInterface leftTree, BinaryTreeInterface
rightTree) - privateSetTree(rootData, (BinaryTree)leftTree,
(BinaryTree)rightTree)
public Object getRootData() public int
getHeight() public int getNumberOfNodes() public
boolean isEmpty() public void clear() public
void setTree(Object rootData) public void
setTree(Object rootData,
BinaryTreeInterface leftTree,
BinaryTreeInterface rightTree) public Iterator
getPreorderIterator() public Iterator
getPostOrderIterator() public Iterator
getInorderIterator() public Iterator
getLevelOrderIterator()
31The BinaryTree ClassprivateSetTree - attempt 1
- private void privateSetTree(rootData, BinaryTree
leftTree, BinaryTree rightTree) -
- root new BinaryNode(rootData)
- if (leftTree ! null) root.setRightChild(leftTr
ee.root) - if (rightTree ! null) root.setRightChild(right
Tree.root)
Problems? Call by reference for the left and
right tree results in the actual subtrees sharing
nodes with the new tree. Solution? Make a copy
of left and right tree before executing the set
methods above. But needs to be a deep copy.
32The BinaryTree ClassprivateSetTree
- Solution set trees to null after assignment,
- Force the user to copy the trees before calling
setTree if its necessary to preserve them - Solution Dont allow the operation
- Theres nothing wrong with not allowing certain
operations, such as divide by zero.
33The BinaryTree ClassprivateSetTree - attempt 2
- private void privateSetTree(Object rootData,
BinaryTree leftTree, BinaryTree rightTree) throws
BinaryTreeException -
- root new BinaryNode(rootData)
- if (this leftTree this rightTree)
throw - new BinaryTreeException("Cant
create tree in privateSetTree") - if (rightTree leftTree) throw new
BinaryTreeException -
("Cant create tree in privateSetTree") - if (leftTree ! null) root.setLeftChild(leftTre
e.root) - if (rightTree ! null) root.setRightChild(right
Tree.root) - leftTree null
- rightTree null
Not consistent with our interface also need to
write the exception class.
34BinaryTreeExceptions
- public class BinaryTreeException extends
Exception -
- public BinaryTreeException()
-
-
- public BinaryTreeException(String s)
- super(s)
35Binary Tree TraversalsinorderTraverse
- private void inorderTraverse(BinaryNode node)
-
- if (node ! null)
-
- System.out.print("(")
- inorderTraverse((BinaryNode)node.getLeftChild
()) - System.out.print(" "node.getData()" ")
- inorderTraverse((BinaryNode)node.getRightChil
d()) - System.out.print(")")
-
-
36Binary Tree Iterators
- Constructor of the iterator pushes the tree nodes
onto a queue or a stack -
- The next method simply pops the stack to get the
next element - Well do a postorderIterator
- You do the preorderIterator and inorderIterator
- Can use our post order traversal methods to get
the iterator
37Binary Tree IteratorspostOrderIterator
- public class PostOrderIterator
- Stack s, temp
- public PostOrderIterator(BinaryTree t) throws
StackFullException, -
StackEmptyException - //pre t ! null
- //post this is an postorder Iterator for all
the elements in t - // the first call to next() will return the
first postorder element of t - s new LinkedStack() temp new
LinkedStack() - BinaryNode current t.getRoot()
- pushNodes(current) //push all nodes onto
stack using postorder traversal - while(!temp.isEmpty()) //reverse node order
since nodes have been -
pushed in postorder - s.push(temp.pop())
-
38Binary Tree IteratorspushNodes
private void pushNodes(BinaryNode n) throws
StackFullException if (n ! null)
pushNodes((BinaryNode)n.getLeftChild())
pushNodes((BinaryNode)n.getRightChild())
temp.push(n)
39Binary Tree IteratorshasNext, next
- public boolean hasNext()
- //post Returns true iff this iteration has more
elements - return !s.isEmpty()
- public Object next() throws NoSuchElementException
, -
StackFullException, StackEmptyException - // pre The structure of the tree this is
iterating has not changed - // since this was constructed.
- // post Returns the next element in the
iteration. - // Throws a NoSuchElementException if !hasNext()
- if (hasNext()) return s.pop()
- else throw new NoSuchElementException()
40Binary Tree Iteratorsremove
- public void remove() throws UnsupportedOperationEx
ception - //post Throws an UnsupportedOperationException
- // (a runTime
Exception) - // (Although defined in the java.util.Iterator
interface, - // it is optional and we will not implement it)
- throw new UnsupportedOperationException()
41The BinaryTree ClassOther Useful Methods
- public void postorderTraverse()
- postorderTraverse(root)
- private void postorderTraverse(BinaryNode node)
-
- if (node ! null)
- postorderTraverse((BinaryNode)node.getLeftChi
ld()) - postorderTraverse((BinaryNode)node.getRightCh
ild()) - System.out.print(node.getData())
-
42The BinaryTree ClassOther Useful Methods
- public void attachLeft(BinaryTree t)
- //pre t is a non-null binary tree
- //post the left child of this tree is set to t
- BinaryNode troot t.getRoot()
- root.setLeftChild(troot)
-
- public void attachRight(BinaryTree t)
- //pre t is a non-null binary tree
- //post the right child of this tree is set to t
- BinaryNode troot t.getRoot()
- root.setRightChild(troot)
43The Complete ImplementationClasses
- Binary Node
- BinaryNodeInterface.java
- BinaryNode.java
- Binary Tree linked implementation
- TreeInterface.java
- TreeIteratorInterface.java
- BinaryTreeInterface.java
- BinaryTree.java
- BinaryTreeException.java
- The Stack linked implementation
- Stack.java
- Node.java
- LinkedStack.java
- StackFullException.java
- StackEmptyException.java
- NoSuchElementException.java
- Test Program
- BinaryTreeTest.java
44The TreeNode Class
- TreeNode has four class variables
- Reference to the parent node
- The element stored there
- A list of children nodes
- A value field (for later applications)
TreeNode Object Object NodeList
TreeNodes!
45insertChild Method
Node C
trailer
X
Node H
ParentC
Element
Value
trailer
header
Children
X
X
ParentH
Element
Node I
Value
trailer
header
Children
X
X
46Enumerating the Children
- Child node Enumerator
- Implements the Enumeration interface
trailer
header
X
X
public Enumeration children(TreeNode n)
return new ListEnumerator(n.getChildren())
47Balanced vs. Unbalanced Trees 1
start
A
B
C
F
G
L
D
H
I
Sort of Balanced
E
Mostly Unbalanced
J
K