CS 261 – Summer 2011 Binary Search Trees

advertisement
CS 261 – Summer 2011
Binary Search Trees
Can we do something useful?
• How can we make a collection using the idea of a binary
tree?
• How about starting with an implementation of a BAG
• Goal: try to make the operations on the collection
proportional to the length of a path, rather than the
number of elements in the tree.
• First step. A Binary Search Tree.
Binary Search Tree
• Binary search trees are binary tree’s where every node’s
object value is:
– Greater than or equal to all its descendants in the left subtree
– Less than or equal to all its descendants in the right subtree
• An in-order traversal will return the elements in sorted
order
• If the tree is reasonably full, searching for an element is
O(log n)
Binary Search Tree: Example
Alex
Abner
Abigail
Angela
Adela
Adam
Alice
Agnes
Audrey
Allen
Arthur
Binary Search Tree (BST): Implementation
struct BST {
struct Node * root;
int size;
};
struct node {
EleType value;
struct node * left;
struct node * right;
};
void BSTinit (struct BST *tree);
void BSTadd(struct BST *tree, EleType value);
int BSTcontains (struct BST *tree, EleType value);
void BSTremove (struct BST *tree, EleType value);
int BSTsze (struct BST *tree);
Implementing the Bag: Contains
• Start at the root.
• At each node, compare to test: return true if match
• If test is less than node, look at left child
• Otherwise if test is greater than node, look at right child
• Traverses a path from the root to the leaf.
• Therefore, if the tree is reasonably complete (an
important if) the execution time is O( ?? )
Implementing a Bag: Add
• Do the same type of traversal from root to leaf.
• When you find a null value, create a new node.
Alex
Abner
Abigail
Angela
Adela
Adam
Alice
Agnes
Audrey
Allen
Arthur
Add just calls the utility routine
…
void BSTadd (struct BST * tree, EleType newValue) {
root = BSTnodeAdd(tree->root, newValue);
tree->size++;
}
What is the complexity? O( ?? )
Could do it with a loop
Struct node * BSTnodeAdd (struct node * current, EleType newValue) {
Struct node * p = current;
If (current == 0) return newNode (newValue, 0, 0);
Else while (p != 0) {
if (newValue < p->value)
if (p->left == 0)
{p->left = newNode(newValue, 0, 0); return;}
else p = p->left;
else
if (p->right == 0)
{ p->right = newNode(newValue, 0, 0); return;}
else p = p->right;
}
return current;
}
newNode makes life a bit easier
struct node * newNode
(EleType newValue, struct node * l, struct node * r)
{
struct node * newnode =
(struct node *) malloc(sizeof(struct node));
assert(newnode != 0);
newnode->value = newValue;
newnode->left = l;
newnode->right = r;
return newnode;
}
An alternative way to look at it
• A useful trick (adapted from the functional programming
world). Make a secondary routine that returns the tree
with the value inserted.
Node add (Node start, EleType newValue)
if start is null then return new Node with value
otherwise if newValue < Node value
left child = add (left child, newValue)
else
right child = add (right child, newValue)
return current node
Bag Implementation: Remove
• As is often the case, remove is the most complex. Leaves
a “hole”. What value should fill the hole?
Alex
Abner
Abigail
Angela
Adela
Adam
Alice
Agnes
Audrey
Allen
Arthur
Who can fill that hole?
• Answer: The Leftmost child of the right child. (Smallest
element in right subtree)
• Try this on a few values.
• Useful to have a couple of internal routines
EleType leftmostChild (struct node * current) {
… // return value of leftmost child of current
}
struct node * removeLeftmostChild (struct node * current)
{
… // return tree with leftmost child removed
}
One additional special case
• We have said you want to fill hole with leftmost child of
right child. What if you don’t have a right child? Think
about it. Can just return left child. Try remove “Audrey”
Angela
Alice
Audrey
Allen
Arthur
Remove: again easy if you return a tree
Node remove (Node current, Object testValue)
if current.value is the thing we seek
if right child is null return left child
else replace value with leftmost child of right child
and set right child to be removeLeftmost (right)
else if testValue < current.value
left child = remove (left child, testValue)
else
right child = remove (right child, testValue)
return current node
What is the complexity??
Basically once more just running down a path from root to
leaf
What is the complexity? O(???)
Careful! What can go wrong? What happens in the worst
case??
Questions?? Now the worksheet.
Download