binary trees like a list, a (binary) tree can be empty or non-empty. in class we will explore a...
Post on 22-Dec-2015
225 views
TRANSCRIPT
Binary Trees
• Like a list, a (binary) tree can be empty or non-empty.
• In class we will explore a state-based implementation, similar to the LRS
• You are expected to read about alternate implementation strategies in the textbook
Method of aBinary Recursive Structure (BRS)
• method to grow tree: insertRoot
• method to shrink tree: removeRoot
• accessor/mutator pair for root: setRoot/getRoot
• accessor/mutator pair for left: setLeft/getLeft
• accessor/mutator pair for right: setRight/getRight
• visitor support: execute
State transitions
• Empty NonEmpty: insertRoot on an empty tree
• NonEmpty Empty: removeRoot from a tree that is a leaf– A leaf is a tree both of whose children are
empty.
• No other state transitions can occur.
Moreover…
• insertRoot throws an exception if called on a nonEmpty tree
• removeRoot throws an exception if called on a non-leaf tree
• Isn’t this very restrictive?
Yes…but
• It is very restrictive, but for good reasons:– What would it mean to add a root to a tree that
already has one?– If you could remove the root from a tree with
nonEmpty children, what would become of those children?
Usage of a BRS
• A BRS is not used “raw”, but is used to implement more specialized trees.
• Consider how we defined the SortedList in terms of the LRS: by composition.
• We will now explore how to define a sorted binary tree (a Binary Search Tree) by composition with a BRS.
Binary Search Tree (BST)
• A binary search tree (BST) is a binary tree which maintains its elements in order.
• The BST order condition requires that, for every non-empty tree, the value at the root is greater than every value in the tree’s left subtree, and less than every value in the tree’s right subtree.
Example 1Does this tree satisfy the BST order condition?
Fred
WilmaBetty
Barney Pebbles
No!Barney < Betty < Pebbles > Fred < Wilma
Fred
WilmaBetty
Barney Pebbles
Example 2Does this tree satisfy the BST order condition?
Fred
WilmaBetty
Barney Pebbles
Yes!Barney < Betty < Fred < Pebbles < Wilma
Fred
WilmaBetty
Barney Pebbles
Example 3Does this tree satisfy the BST order condition?
Fred
WilmaBetty
Barney Pebbles
No!Betty > Barney < Fred < Pebbles < Wilma
Fred
WilmaBetty
Barney Pebbles
Example 4…but if we swap Betty & Barney, we restore order!
Fred
Wilma
Betty
Barney
Pebbles
Operations on a BST
• public BST insert(Comparable item)
• public BST remove(Comparable item)
• public boolean member(Comparable item)
• How do we support these? They don’t exist as methods on the BRS.
Visitors to the rescue!
• Visitors on the BRS have the same basic structure as on the LRS: they deal with two cases:
– public Object emptyCase(BRS host, Object inp)
– public Object nonEmptyCase(BRS host, Object inp)
Example: toStringVisitor
public class ToStringVisitor extends IAlgo {
public static final ToStringVisitor SINGLETON = new ToStringVisitor();
private ToStringVisitor() {}
public Object emptyCase(BRS host, Object input) {return "[]";
}
public Object nonEmptyCase(BRS host, Object input) { return "[" + host.getLeft().execute(this, null) + " " + host.getRoot().toString() + " "
+ host.getRight().execute(this, null) + "]";}
}
Back to the BST
• Let’s first consider the insert operation.• We must consider two possibilities:
– the underlying BRS is empty• just insertRoot
– the underlying BRS is nonEmpty• we can’t insertRoot, because the BRS is nonEmpty• compare new item with root – determine whether
new item belongs in left or right subtree – insert recursively into correct subtree
A first cut at the visitor
public class InsertVisitor extends IAlgo {
public Object emptyCase(BRS host, Object item) {return host.insertRoot(item);
}
public Object nonEmptyCase(BRS host, Object item) {if ( ((Comparable) item).compareTo(host.getRoot()) < 0 ) {
// item belongs in left subtreereturn host.getLeft().execute(this, item);
}else if ( ((Comparable) item).compareTo(host.getRoot()) > 0 ) {
// item belongs in right subtreereturn host.getRight().execute(this, item);
}else { // item is already in tree (Note UNIQUENESS ASSUMPTION)
return host;}
}}
How about determining membership for an item?
• We must consider two possibilities:– the underlying BRS is empty
• just item was not found
– the underlying BRS is nonEmpty• compare new item with root – determine whether
new item has been found, or whether it would be in left or right subtree – look recursively into correct subtree
A first cut at the visitor
public class MemberVisitor extends IAlgo {
public Object emptyCase(BRS host, Object item) {return new Boolean(false);
}
public Object nonEmptyCase(BRS host, Object item) {if ( ((Comparable) item).compareTo(host.getRoot()) < 0 ) {
// item belongs in left subtreereturn host.getLeft().execute(this, item);
}else if ( ((Comparable) item).compareTo(host.getRoot()) > 0 ) {
// item belongs in right subtreereturn host.getRight().execute(this, item);
}else { // item is already in tree (Note UNIQUENESS ASSUMPTION)
return new Boolean(true);}
}}
Did you notice similarity?
• The structure of the insert and membership visitors was the same.
• A small number of details differed.
• Let’s unify!
The find visitor
public class Find extends IAlgo {
public Object emptyCase(BRS host, Object item) {return host;
}
public Object nonEmptyCase(BRS host, Object item) {if ( ((Comparable) item).compareTo(host.getRoot()) < 0 ) {
// item belongs in left subtreereturn host.getLeft().execute(this, item);
}else if ( ((Comparable) item).compareTo(host.getRoot()) > 0 ) {
// item belongs in right subtreereturn host.getRight().execute(this, item);
}else { // item is already in tree (Note UNIQUENESS ASSUMPTION)
return host;}
}}
Look at BST implementation
• insert, remove and member ALL make use of the same Find visitor:– first find the insertionPoint, – then do the right thing.
The insert method
public BST insert(Comparable item) {
BRS insertPoint = (BRS) _tree.execute(new Find(), item);
only insert item into insertPoint if empty (duplicates ignored)
return this;
}
The insert method
public BST insert(Comparable item) {
BRS insertPoint = (BRS) _tree.execute(new Find(), item);
insertPoint.execute(new IAlgo() {
public Object emptyCase(BRS host, Object input) {
host.insertRoot(input);
return null;
}
public Object nonEmptyCase(BRS host, Object input) {
return null;
}
}, item);
return this;
}
The member method
public boolean member(Comparable item) {
BRS insertPoint = (BRS) _tree.execute(new Find(), item);
return whether insertPoint is empty or nonEmpty
}
The member method
public boolean member(Comparable item) {
BRS insertPoint = (BRS) _tree.execute(new Find(), item);
return ((Boolean) insertPoint.execute(new IAlgo() {public Object emptyCase(BRS host, Object input) {
return new Boolean(false);
}
public Object nonEmptyCase(BRS host, Object input) {return new Boolean(true);
}
}, null)).booleanValue();
}
The remove methodpublic BST remove(final Comparable item) {
BRS removePoint = (BRS) _tree.execute(new Find(), item);
handle removal differently in five different cases:
empty tree
non-empty tree with both children empty (leaf case)
non-empty tree with left child empty, right child non-empty
non-empty tree with left child non-empty, right child empty
non-empty tree with both children non-empty
return this;
}
The remove methodpublic BST remove(final Comparable item) {
BRS removePoint = (BRS) _tree.execute(new Find(), item);
removePoint.execute(new FiveStateVisitor() {private IAlgo theRemovalVisitor = this;public Object emptyCase(BRS host, Object input) {
return host;}public Object leafCase(BRS host, Object input) {
host.removeRoot();return host;
}public Object leftNonEmptyCase(BRS host, Object input) {
host.setRoot(host.getLeft().getRoot());host.setRight(host.getLeft().getRight());host.setLeft(host.getLeft().getLeft());return host;
}public Object rightNonEmptyCase(BRS host, Object input) {
host.setRoot(host.getRight().getRoot());host.setLeft(host.getRight().getLeft());host.setRight(host.getRight().getRight());return host;
}public Object leftRightNonEmptyCase(BRS host, Object input) {
Object smallestInRight = host.getRight().execute(new IAlgo() {public Object emptyCase(BRS host, Object parent) {
Object smallest = ((BRS) parent).getRoot();((BRS) parent).execute(theRemovalVisitor, null);return smallest;
}public Object nonEmptyCase(BRS host, Object parent) {
return host.getLeft().execute(this, host);}
}, null);host.setRoot(smallestInRight);return host;
}}, item);return this;
}
Question
How do we make the 5-way distinction?
See the FiveStateVisitor definition in the lecture code repository.
Basic idea: check left, then check right.