Presentation is loading. Please wait.

Presentation is loading. Please wait.

CMSC 341 Binary Search Trees 5/28/2019.

Similar presentations


Presentation on theme: "CMSC 341 Binary Search Trees 5/28/2019."— Presentation transcript:

1 CMSC 341 Binary Search Trees 5/28/2019

2 Binary Search Tree A Binary Search Tree is a Binary Tree in which, at every node v, the value stored in the left child node is less than the value at v and the value stored in the right child is greater. The elements in the BST must be comparable. Duplicates are not allowed. 5/28/2019

3 BST Implementation The SearchTree ADT
A search tree is a binary search tree in which are stored 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 tree Each BST maintains a simple object, known as ITEM_NOT_FOUND, that is guaranteed to not be an element of the tree. ITEM_NOT_FOUND is provided to the constructor. (author’s code) 5/28/2019

4 BinarySearchTree class
template <class Comparable> class BinarySearchTree { public: BinarySearchTree(const Comparable &notFnd); BinarySearchTree (const BinarySearchTree &rhs); ~BinarySearchTree(); const Comparable &findMin() const; const Comparable &findMax() const; const Comparable &find(const Comparable &x) const; bool isEmpty() const; void printTree() const; void makeEmpty(); void insert (const Comparable &x); void remove (const Comparable &x); const BinarySearchTree &operator=(const BinarySearchTree &rhs); 5/28/2019

5 BinarySearchTree class (cont)
private: BinaryNode<Comparable> *root; const Comparable ITEM_NOT_FOUND; const Comparable& elementAt(BinaryNode<Comparable> *t) const; void insert (const Comparable &x, BinaryNode<Comparable> * &t) const; void remove (const Comparable &x, BinaryNode<Comparable> * &t) const; BinaryNode<Comparable> *findMin(BinaryNode<Comparable> *t const; BinaryNode<Comparable> *findMax(BinaryNode<Comparable> *t)const; BinaryNode<Comparable> *find(const Comparable &x, BinaryNode<Comparable> *t) const; void makeEmpty(BinaryNode<Comparable> *&t) const; void printTree(BinaryNode<Comparable *t) const; BinaryNode<Comparable> *clone(BinaryNode<Comparable> *t)const; }; 5/28/2019

6 BinarySearchTree Implementation
template <class Comparable> const Comparable &BinarySearchTree<Comparable> :: find(const Comparable &x) const { return elementAt(find (x, root)); } elementAt(BinaryNode<Comparable> *t) const { return t == NULL ? ITEM_NOT_FOUND : t->element; BinaryNode<Comparable> *BinarySearchTree<Comparable> :: find(const Comparable &x, BinaryNode<Comparable> *t) const { if (t == NULL) return NULL; else if (x < t->element) return find(x, t->left); else if (t->element < x) return find(x, t->right); else return t; // Match Public find operation calls private find operation. The private find operation recursively searches the tree. If element is found, a pointer to its node is returned. Otherwise, NULL is returned. If NULL is returned to the public find method, it then returns Item_Not_Found. Otherwise, it returns the element of the node. What about strategy of returning Item_Not_Found? Alternative strategies mentioned in text: find throws an exception find has a bool reference paramenter to indicate success/failure Discuss pros/cons Another approach (like that for lists) Find returns an iterator that points to the found element. If the element is not found, the iterator is PastEnd.

7 Performance of find Search in randomly built BST is O(lg n) on average
but generally, a BST is not randomly built Asymptotic performance is O(h) 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 5/28/2019

8 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 thatdoes not have v in its left subtree 5/28/2019

9 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 5/28/2019

10 The remove Operation } template <class Comparable>
void BinarySearchTree<Comparable>:: remove(const Comparable &x, BinaryNode<Comparable> *&t) const { if (t == NULL) return; // item 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)) { t->element = findMin( (t->right)->element ); remove (t->element, t->right);} else { BinaryNode<Comparable> *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.

11 The insert Operation template <class Comparable>
void BinarySearchTree<Comparable>:: insert(const Comparable &x) // public insert( ) { insert (x, root); // calls private insert( ) } insert(const Comparable &x, BinaryNode<Comparable> *&t) const { if (t == NULL) t = new BinaryNode<Comparable>(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.

12 Implementation of makeEmpty
template <class 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) 5/28/2019

13 Tree Iterators Could provide separate iterators for each desired order
Iterator<T> *GetInorderIterator(); Iterator<T> *GetPreorderIterator(); Iterator<T> *GetPostorderIterator (); Iterator<T> *GetLevelorderIterator (); 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) 5/28/2019

14 Tree Iterator Implementation
Approach 1: Store traversal in list. Return list iterator for list. Iterator<T> BinaryTree::GetInorderIterator() { List<T> *lst = new ArrayList<T>; FullListInorder(list, getRoot()); return list->GetIterator(); } void FillListInorder(ArrayList<T> *lst, Bnode<T> *node) { if (node == NULL) return; FillListInorder(list, node->left); lst->Append(node->data); FillListInorder(lst, node->right); 5/28/2019

15 Tree Iterators (cont) Approach 2: store traversal in stack to mimic recursive traversal template <class T> class InOrderIterator : public Iterator { private: Stack<T> _stack; BinaryTree<T> *_tree; public: InOrderIterator(BinaryTree<T> *t); bool hasNext() {return (!_stack.isEmpty()); } T Next(); }; 5/28/2019

16 Tree Iterators (cont’d)
template <class T> InOrderIterator<T>::InOrderIterator(BinaryTree<T> *t) { _tree = t; Bnode<T> *v = t->getRoot(); while (v != NULL) { _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 5/28/2019

17 Tree Iterators (cont’d)
template <class T> T InOrderIterator<T>::Next() { Bnode<T> *top = _stack.Top(); _stack.Pop(); Bnode<T> *v = top->right; while (v != NULL) { _stack.Push(v); // push right child v = v->left; // and all left descendants } return top->element; 5/28/2019


Download ppt "CMSC 341 Binary Search Trees 5/28/2019."

Similar presentations


Ads by Google