Download presentation
Presentation is loading. Please wait.
1
CMSC 341 Binary Search Trees 2/21/2006
2
Binary Search Tree A Binary Search Tree is a Binary Tree in which, at every node v, the values stored in the left subtree of v are less than the value at v and the values stored in the right subtree are greater. The elements in the BST must be comparable. Duplicates are not allowed in our discussion. Note that each subtree of a BST is also a BST. 2/21/2006
3
A BST of integers 42 20 50 60 99 35 32 27 25 A B C D A = all values less than 20 B = values less than 32, but larger than 27. Eg 28 – 31 C = values larger than 60, but less than 99 D = values larger than 99 Describe the values which might appear in the subtrees labeled A, B, C, and D 2/21/2006
4
BST Implementation The SearchTree ADT
A search tree is a binary search tree which stores homogeneous elements with no duplicates. It is dynamic. The elements are ordered in the following ways inorder -- as dictated by operator< preorder, postorder, levelorder -- as dictated by the structure of the trer 2/21/2006
5
BST Implementation template <typename Comparable>
class BinarySearchTree { public: BinarySearchTree( ); BinarySearchTree( const BinarySearchTree & rhs ); ~BinarySearchTree( ); const Comparable & findMin( ) const; const Comparable & findMax( ) const; bool contains( const Comparable & x ) const; bool isEmpty( ) const; void printTree( ) const; void makeEmpty( ); void insert( const Comparable & x ); void remove( const Comparable & x ); 2/21/2006
6
BST Implementation (2) const BinarySearchTree &
operator=( const BinarySearchTree & rhs ); private: struct BinaryNode { Comparable element; BinaryNode *left; BinaryNode *right; BinaryNode( const Comparable & theElement, BinaryNode *lt, BinaryNode *rt ) :element( theElement ), left( lt ), right( rt) { } }; 2/21/2006
7
BST Implementation (3) // private data BinaryNode *root;
// private recursive functions void insert( const Comparable & x, BinaryNode * & t ) const; void remove(const Comparable & x, BinaryNode * & t ) const; BinaryNode * findMin( BinaryNode *t ) const; BinaryNode * findMax( BinaryNode *t ) const; bool contains( const Comparable & x, BinaryNode *t ) const; void makeEmpty( BinaryNode * & t ); void printTree( BinaryNode *t ) const; BinaryNode * clone( BinaryNode *t ) const; }; 2/21/2006
8
BST “contains” method // Returns true if x is found (contained) in the tree. bool contains( const Comparable & x ) const { return contains( x, root ); } // Internal (private) method to test if an item is in a subtree. // x is item to search for. // t is the node that roots the subtree. bool contains( const Comparable & x, BinaryNode *t ) const if( t == NULL ) return false; else if( x < t->element ) return contains( x, t->left ); else if( t->element < x ) return contains( x, t->right ); else return true; // Match 2/21/2006
9
Performance of “contains”
Searching in randomly built BST is O(lg n) on average but generally, a BST is not randomly built Asymptotic performance is O(height) in all cases Elements inserted in the order: 50,40,30,20,10 avg search time: = 10 Elements inserted in order: 30,20,10,40,50 avg search time: =6 How many permutations of 5 things? 5! = 120 must look at average IPL of the120 trees 2/21/2006
10
Predecessor in BST Predecessor of a node v in a BST is the node that holds the data value that immediately precedes the data at v in order. Finding predecessor v has a left subtree then predecessor must be the largest value in the left subtree (the rightmost node in the left subtree) v does not have a left subtree predecessor is the first node on path back to root that does not have v in its left subtree 2/21/2006
11
Successor in BST Successor of a node v in a BST is the node that holds the data value that immediately follows the data at v in order. Finding Successor v has right subtree successor is smallest value in right subtree (the leftmost node in the right subtree) v does not have right subtree successor is first node on path back to root that does not have v in its right subtree 2/21/2006
12
The remove Operation // Internal (private) method to remove from a subtree. // x is the item to remove. // t is the node that roots the subtree. // Set the new root of the subtree. void remove( const Comparable & x, BinaryNode * & t ) { if( t == NULL ) return; // x not found; do nothing if( x < t->element ) remove( x, t->left ); else if( t->element < x ) remove( x, t->right ); else if( t->left != NULL && t->right != NULL ) // two children t->element = findMin( t->right )->element; remove( t->element, t->right ); } else // zero or one child BinaryNode *oldNode = t; t = ( t->left != NULL ) ? t->left : t->right; delete oldNode; Constraint: delete a node, maintain BST property 1. Deleting a leaf. Easy. Just do it. BST property is not affected. 2. Deleting a non-leaf node v a. v has no left child -- replace v by its right child b. v has no right child -- replace v by its left child c. v has both left and right children, either: 1. Replace data in v by data of predecessor and delete predecessor 2. Replace data in v by data in successor and delete successor Note that private remove method takes a reference to a pointer to a node. This allows the pointer to be changed to point to another node. If this were not a reference to a pointer, the pointer would be passed by value and could not be changed inside the method ie the last else clause t = (t->left != NULL) ? T->left : t->right; would change to t inside the method, but not cause any change after the method returns. Asymptotic performance of remove is similar to that for find. It’s O(n) worst case and O(lg n) best/average case. Remove traverses tree from root to some leaf.
13
The insert Operation // Internal method to insert into a subtree.
// x is the item to insert. // t is the node that roots the subtree. // Set the new root of the subtree. void insert( const Comparable & x, BinaryNode * & t ) { if( t == NULL ) t = new BinaryNode( x, NULL, NULL ); else if( x < t->element ) insert( x, t->left ); else if( t->element < x ) insert( x, t->right ); else ; // Duplicate; do nothing } Method: recursively traverses the tree looking for a null pointer at the point of insertion. If found, constructs a new node and stitches it into the tree. If duplicate found, simply returns with no insertion done. Question: Suppose Item_Not_Found object is inserted? The insert code allows it. This would mean the find operation could no longer indicate an unsuccessful search. Esoteric but possible -- and a reason not to use the text’s approach to indicating unsuccessful search. Asymptotic performance of insert = O(n) as usual. 2/21/2006
14
Implementation of makeEmpty
template <typename Comparable> void BinarySearchTree<Comparable>:: makeEmpty( ) // public makeEmpty ( ) { makeEmpty( root ); // calls private makeEmpty ( ) } makeEmpty( BinaryNode<Comparable> *& t ) const if ( t != NULL ) { // post order traversal makeEmpty ( t->left ); makeEmpty ( t->right ); delete t; t = NULL; Must hang onto each node until its children are deleted Postorder traversal is used in makeEmpty Asymptotic performance = O(n) Traversals of theentire tree (pre, post, in, level) require that each node be visited. Since n nodes are visited, operation is O(n) 2/21/2006
15
Implementation of Assignment Operator
// operator= makes a deep copy via cloning const BinarySearchTree & operator=( const BinarySearchTree & rhs ) { if( this != &rhs ) makeEmpty( ); // free LHS nodes first root = clone( rhs.root ); // make a copy of rhs } return *this; //Internal method to clone subtree -- note the recursion BinaryNode * clone( BinaryNode *t ) const if( t == NULL ) return NULL; return new BinaryNode(t->element, clone(t->left), clone(t->right); 2/21/2006
16
Performance of BST methods
What is the asymptotic performance of each of the BST methods? Best Case Worst Case Average Case contains insert remove findMin/Max makeEmpty assignment 2/21/2006
17
Building a BST Given an array/vector of elements, what is the performance (best/worst/average) of building a BST from scratch? 2/21/2006
18
Tree Iterators As we know there are several ways to traverse through a BST. For the user to do so, we must supply different kind of iterators. The iterator type defines how the elements are traversed. InOrderIterator<T> *InOrderBegin( ); PerOrderIterator<T> *PreOrderBegin( ); PostOrderIterator<T> *PostOrderBegin ( ); LevelOrderIterator<T> *LevelOrderBegin( ); Approach 1: Easy to code using existing list iterators. But: O(n) storage for the list (can do better) Difficult to free list storage when iterator is deleted (memory leak) 2/21/2006
19
Using Tree Iterator main ( ) { Tree<int> tree;
// store some ints into the tree InOrderIterator<int> itr = tree.InOrderBegin( ); while (itr.HasNext( )) int x = itr.Next( ); // do something with x } 2/21/2006
20
InOrder Tree Iterator Implementation
Approach 1: Store traversal in list (private data member). Return iterator for list. template <typename T> InOrderIterator<T> BinaryTree::InorderBegin( ) { m_theList = new List<T>; FillListInorder(m_theList, getRoot( ) ); return m_theList->GetIterator( ); } void FillListInorder(List<T> *lst, BinaryNode<T> *node) if (node == NULL) return; FillListInorder( lst, node->left ); lst->Append( node->data ); FillListInorder( lst, node->right ); 2/21/2006
21
InOrder Tree Iterator Implemenation (2)
Approach 2: store traversal in stack to mimic recursive traversal template <typename T> class InOrderIterator { private: Stack<* BinaryNode<T> > m_stack; public: InOrderIterator(BinaryNode<T> *t); bool HasNext() // aka end( ) {return !m_stack.isEmpty(); } T Next(); // aka op++ }; 2/21/2006
22
InOrder Tree Iterator Implementation (3)
template <class T> InOrderIterator<T>::InOrderIterator( BinaryNode<T> *t ) { BinaryNode<T> *v = t->GetRoot(); while (v != NULL) { m_stack.Push(v); // push root v = v->left; // and all left descendants } Example: 50 30 80 O(h) stoarage (=O(lg n) in best and avg cases) Easy to free stack (destroyed when iterator is destroyed) More difficult to code Similar code for re-order and post-order 2/21/2006
23
InOrder Tree Iterator Implementation (4)
template <typename T> T InOrderIterator<T>::Next() { BinaryNode<T> *top = m_stack.Top(); m_stack.Pop(); BinaryNode<T> *v = top->right; while (v != NULL) { m_stack.Push(v); // push right child v = v->left; // and all left descendants } return top->element; 2/21/2006
24
More Recursive Binary (Search) Tree Functions
bool isBST ( BinaryNode<T> *t ) returns true if the Binary tree is a BST const T& findMin( BinaryNode<T> *t ) returns the minimum value in a BST int CountFullNodes ( BinaryNode<T> *t ) returns the number of full nodes (those with 2 children) in a binary tree int CountLeaves( BinaryNode<T> *t ) counts the number of leaves in a Binary Tree 2/21/2006
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.