Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
CMPSCI 187
Introduction to Programming
with Data Structures
Computer Science 187
Lecture 17: Implementing Trees
Announcements
1. Current OWL and project 4 are due
today (November 8).
2. New programming project up soon.
3. New OWL up soon.
1
CMPSCI 187
General Tree Interfaces
General Tree Interface
Interface for traversals
of general trees
public interface TreeInterface
public interface TreeIteratorInterface
{
{
public Object getData();
public Iterator PreorderIterator();
public int getHeight();
public Iterator PostOrderIterator();
public int getNumberOfNodes();
public Iterator InorderIterator();
public boolean isEmpty();
public Iterator LevelOrderIterator();
public void clear();
}
}
2
CMPSCI 187
Binary Tree interface
methods 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();
public Iterator PostOrderIterator();
public Iterator InorderIterator();
public Iterator LevelOrderIterator();
3
CMPSCI 187
The 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?
4
CMPSCI 187
…and 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(); //returns 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.
}
5
CMPSCI 187
The methods of the interfaces
BinaryTreeInterface
BinaryNodeInterface
public Object getData();
public Object getData();
public int getHeight();
public void setData(Object myElement);
public int getNumberOfNodes();
public void setLeftChild(BinaryNodeInterface myLeft);
public boolean isEmpty();
public void setRightChild(BinaryNodeInterface myRight);
public void clear();
public BinaryNodeInterface getLeftChild();
public void setTree(Object rootData);
public BinaryNodeInterface getRightChild();
public void setTree(Object rootData,
public boolean hasLeftChild();
BinaryTreeInterface leftTree,
public boolean hasRightChild();
BinaryTreeInterface rightTree);
public boolean isLeaf();
public Iterator PreorderIterator();
public Iterator PostOrderIterator();
public Iterator InorderIterator();
public Iterator LevelOrderIterator();
6
CMPSCI 187
An 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();
t:
tree1:
4
1
2
5
7
CMPSCI 187
Example, 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();
7
8
3
tree3:
6
BinaryTree tree3 = new BinaryTree();
tree3.setTree(new Integer(3), tree2, null);
System.out.println("Tree3 is: ");
tree3.inorderTraverse();
System.out.println();
BinaryTree tree4=new BinaryTree();
tree4.setTree(new Integer (1), tree1, tree3);
System.out.println("Final tree is: ");
tree4.inorderTraverse();
System.out.println();
}}
6
tree2:
7
tree4:
8
1
2
4
3
5
6
7
8
8
CMPSCI 187
Using ‘attach’
//tree4.setTree(new Integer (1), tree1, tree3);
BinaryTree tree4=new BinaryTree(new Integer(1));
tree4.attachLeft(tree1);
tree4.attachRight(tree3);
System.out.println("Final tree is: ");
tree4:
tree4.inorderTraverse();
System.out.println();
2
4
1
3
5
6
7
8
9
CMPSCI 187
Something 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();
tree4:
1
2
What’s the output?
4
3
5
6
7
8
10
CMPSCI 187
Traversing 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).
root
A
B
C
D
H
E
I
J
F
K
G
L
What are some of the possible visitation patterns we
could use?
11
CMPSCI 187
Tree Traversal Patterns
root
A
1
A Possible Pattern
B
2
Touch* Root Node
Visit Left subtree
D
3
Visit Right subtree
Must be applied at
all levels of the
tree.
C
9
H
4
E
6
I
5
J
7
F
10
K
8
G
11
L
12
Called a PreOrder Traversal
*”touch” means doing something at the node, such as printing the element there.
12
CMPSCI 187
preorderTraverse( )
public void preorderTraverse()
{ preorderTraverse(root);}
t:
1
2
private void preorderTraverse(BinaryNode node)
{
4
if (node != null)
{
System.out.print(node.getData()+" ");
preorderTraverse((BinaryNode)node.getLeftChild());
preorderTraverse((BinaryNode)node.getRightChild());
Note the casts…..
}
}
3
5
6
7
8
Print tree using preorder traversal:
1 2 4 5 3 6 7 8
13
CMPSCI 187
Tree Traversal Patterns
root
A
8
A Possible Pattern
Visit Left subtree
B
4
Touch Root node
Visit Right subtree
Must be applied at all
levels of the tree.
C
10
D
2
H
1
E
6
I
3
J
5
F
9
K
7
G
11
L
12
Called an InOrder Traversal
14
CMPSCI 187
inorderTraverse()
public void inorderTraverse()
{ inorderTraverse(root);}
t:
1
2
private void inorderTraverse(BinaryNode node)
4
{
if (node != null)
{
inorderTraverse((BinaryNode)node.getLeftChild());
System.out.print(node.getData()+" ");
inorderTraverse((BinaryNode)node.getRightChild());
}
}
3
5
6
7
Print tree using inorder traversal:
4 2 5 1 7 6 8 3
8
15
CMPSCI 187
Tree Traversal Patterns
root
A
A Possible Pattern
12
B
7
Visit Left subtree
Visit Right subtree
D
3
Touch Root Node
Must be applied at
all levels of the
tree.
C
11
H
1
E
6
I
2
J
4
F
8
K
5
G
10
L
9
Called a PostOrder Traversal
16
CMPSCI 187
postorderTraverse( )
public void postorderTraverse()
{ postorderTraverse(root);}
t:
1
2
private void postorderTraverse(BinaryNode node)
4
{
if (node != null)
{
postorderTraverse((BinaryNode)node.getLeftChild());
postorderTraverse((BinaryNode)node.getRightChild());
System.out.print(node.getData()+” “);
}
}
3
5
6
7
8
Print tree using postorder traversal:
4 5 2 7 8 6 3 1
17
CMPSCI 187
The 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;
18
right = rightChild;}
CMPSCI 187
The BinaryNode Class
public boolean isLeaf()
{ return ((left == null) && (right == null)); }
public Object getData()
{ return data;}
public void setData(Object newData)
{ data=newData;}
public void setLeftChild(BinaryNodeInterface leftChild)
{ left = (BinaryNode) leftChild;}
public BinaryNodeInterface getLeftChild()
{ return left;}
19
CMPSCI 187
The 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
20
CMPSCI 187
The BinaryTree Class
import java.util.*
public class BinaryTree implements BinaryTreeInterface,
java.io.Serializable
{
//Implements a binary tree using the BinaryNode class
protected BinaryNode root;
••
•
21
CMPSCI 187
The BinaryTree Class:
Constructors
//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(rootData, leftTree, rightTree);}
••
•
22
The BinaryTree Class:
CMPSCI 187
getRootData
public Object getRootData()
{ Object rootData = null;
if (root != null) rootData=root.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();
Null data at root or
no root at all?
EXCEPTIONS????
public Iterator getInorderIterator();
public Iterator getLevelOrderIterator();
23
CMPSCI 187
The getHeight() method
getHeight() should be a tree
method e.g. T.getHeight()
public int getHeight()
{
return getHeight(root);
}
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
We should use this mechanism on MOST tree methods that need a node argument.
24
CMPSCI 187
The 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 Object getRootData();
public int getHeight()
{return getHeight(root);}
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();
25
CMPSCI 187
The 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; }
26
The BinaryNode Class:
CMPSCI 187
getNumberOfNodes
Number of nodes in a tree is 1 + number in
left tree + number in right tree
Another naturally recursive method
public Object getRootData();
public int getHeight();
public int getNumberOfNodes()
{return getNumberOfNodes(root);}
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();
27
CMPSCI 187
The BinaryTree Class:
getNumberOfNodes
private int getNumberOfNodes(BinaryNode node)
{ int leftNumber = 0;
int rightNumber = 0;
if ((BinaryNode)node.getLeftChild() !=null)
leftNumber=getNumberOfNodes(
(BinaryNode)node.getLeftChild());
if ((BinaryNode)node.getRightChild() != null)
rightNumber=getNumberOfNodes(
(BinaryNode)node.getRightChild());
return 1+leftNumber+rightNumber;}
28
CMPSCI 187
The BinaryTree Class:
isEmpty, clear
public boolean isEmpty()
{ return root==null;}
public Object getRootData();
public int getHeight();
public void clear()
{ root = null;}
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();
29
CMPSCI 187
The BinaryTree Class:
setTree
public void setTree(Object rootData)
{ root=new 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();
30
CMPSCI 187
The BinaryTree Class:
privateSetTree - attempt 1
private void privateSetTree(rootData, BinaryTree leftTree,
BinaryTree rightTree)
{
root = new BinaryNode(rootData);
if (leftTree != null) root.setRightChild(leftTree.root);
if (rightTree != null) root.setRightChild(rightTree.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.
31
The BinaryTree Class:
CMPSCI 187
privateSetTree
Solution: set trees to null after assignment,
Force
the user to copy the trees before calling
setTree if it’s necessary to preserve them
Solution: Don’t allow the operation
There’s
nothing wrong with not allowing certain
operations, such as divide by zero.
32
CMPSCI 187
The BinaryTree Class:
privateSetTree - 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("Can’t create tree in privateSetTree");
if (rightTree == leftTree) throw new BinaryTreeException
("Can’t create tree in privateSetTree");
if (leftTree != null) root.setLeftChild(leftTree.root);
if (rightTree != null) root.setRightChild(rightTree.root);
leftTree = null;
rightTree = null;
}
Not consistent with our interface; also need to
write the exception class.
33
CMPSCI 187
BinaryTreeExceptions
public class BinaryTreeException extends Exception
{
public BinaryTreeException()
{}
public BinaryTreeException(String s)
{super(s);}
}
34
CMPSCI 187
Binary Tree Traversals
inorderTraverse
private void inorderTraverse(BinaryNode node)
{
if (node != null)
{
System.out.print("(");
inorderTraverse((BinaryNode)node.getLeftChild());
System.out.print(" "+node.getData()+" ");
inorderTraverse((BinaryNode)node.getRightChild());
System.out.print(")");
}
}
35
CMPSCI 187
Binary 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
We’ll do a postorderIterator
You do the preorderIterator and inorderIterator
Can use our post order traversal methods to get the
iterator
36
CMPSCI 187
Binary Tree Iterators
postOrderIterator
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());
}
37
CMPSCI 187
Binary Tree Iterators
pushNodes
private void pushNodes(BinaryNode n) throws StackFullException
{
if (n != null)
{
pushNodes((BinaryNode)n.getLeftChild());
pushNodes((BinaryNode)n.getRightChild());
temp.push(n);
}
}
38
CMPSCI 187
Binary Tree Iterators
hasNext, 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(); }
}
39
CMPSCI 187
Binary Tree Iterators
remove
public void remove() throws
UnsupportedOperationException
//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(); }
40
CMPSCI 187
The BinaryTree Class:
Other Useful Methods
public void postorderTraverse()
{ postorderTraverse(root);}
private void postorderTraverse(BinaryNode node)
{
if (node != null)
{ postorderTraverse((BinaryNode)node.getLeftChild());
postorderTraverse((BinaryNode)node.getRightChild());
System.out.print(node.getData());
}
}
41
CMPSCI 187
The BinaryTree Class:
Other 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);
}
42
CMPSCI 187
The Complete Implementation
Classes
Binary Node
Binary Tree [linked implementation]
TreeInterface.java
TreeIteratorInterface.java
BinaryTreeInterface.java
BinaryTree.java
BinaryTreeException.java
The Stack [linked implementation]
BinaryNodeInterface.java
BinaryNode.java
Stack.java
Node.java
LinkedStack.java
StackFullException.java
StackEmptyException.java
NoSuchElementException.java
Test Program
BinaryTreeTest.java
43
CMPSCI 187
The 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
Parent
Element
Value
Children
header
X
TreeNodes!
trailer
X
44
CMPSCI 187
insertChild Method
Node C
trailer
••••
X
Node H
Parent:C
Element
Value
Children
trailer
header
X
X
Parent:H
Node I
Element
Value
Children
header trailer
X
X
45
CMPSCI 187
Enumerating the Children
Child node Enumerator
Implements the Enumeration interface
Parent
Element
Value
Children
header
X
trailer
X
public Enumeration children(TreeNode n)
{
return new ListEnumerator(n.getChildren());
}
46
CMPSCI 187
Balanced vs. Unbalanced Trees 1
start
A
B
root
C
A
F
B
G
C
L
D
E
F
G
D
H
I
J
K
L
H
I
Sort of Balanced
E
Mostly Unbalanced
J
K
47