1 / 23

CS 261 – Fall 2009

CS 261 – Fall 2009. Binary Search Trees Again, but in detail. Binary Search Tree. Binary search trees are binary tree’s where every node’s object value is: Greater than or equal to all its descendents in the left subtree Less than or equal to all its descendents in the right subtree

Download Presentation

CS 261 – Fall 2009

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. CS 261 – Fall 2009 Binary Search Trees Again, but in detail

  2. Binary Search Tree • Binary search trees are binary tree’s where every node’s object value is: • Greater than or equal to all its descendents in the left subtree • Less than or equal to all its descendents 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)

  3. Alex Abner Angela Abigail Adela Alice Audrey Adam Agnes Allen Arthur Binary Search Tree: Example

  4. 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);

  5. Init - what needs to be done? struct BST { struct node * root; int size; }; void BSTinit (struct BST *tree) { tree->root = 0; tree->size = 0; }

  6. 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( ?? )

  7. Use Recursion, or use a loop? • Both will work. Lets compare the two int BSTcontains (struct BST *tree, EleType value) { struct node * current = tree->root; while (current != 0) { if (EQ(value, current->value)) return 1; if (LT(value, current->value)) current = current->left; else current = current->right; } return 0; }

  8. Recursive version int BSTcontains (struct BST *tree, EleType value) { return BSTnodecontains(tree->root, value); } int BSTnodeContains (struct BST *current, EleType value) { if (current == 0) return 0; if (EQ(value, current->value)) return 1; if (LT(value, current->value)) return BSTnodeContains(current->left, value); else return BSTnodeContains(current->right, value); }

  9. Which is easier to understand? • Somewhat a matter of style • It is what you are used to • Execution time will be very similar

  10. Alex Abner Angela Abigail Adela Alice Audrey Adam Agnes Allen Arthur Implementing a Bag: Add • Do the same type of traversal from root to leaf. • When you find a null value, create a new node.

  11. A useful trick • A useful trick (adapted from the functional programming world). Make a secondary routine that returns the tree with the value inserted. Node add (Node current, EleType newValue) if current 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

  12. Add just calls the utility routine void BSTadd (EleType newValue) { root = _BSTnodeAdd(root, newValue); dataSize++; }

  13. Real work is done inside Node struct node * BSTnodeAdd (struct node * current, EleType value) { if (current == 0) { current = (struct node *) malloc(sizeof(struct node)); assert(current != 0); current->value = value; current->left = current->right = 0; } else if (LT(value, current->value)) current->left = BSTnodeAdd(current->left, value); else current->right = BSTnodeAdd(current->right, value); return current; }

  14. Notes on Add • See how it returns the Current value, the tree AFTER the insertion is made • Again, could be done with a loop - some people find the recursive version easier, some people find the loop easier. • Try writing it using a loop

  15. Alex Abner Angela Abigail Adela Alice Audrey Adam Agnes Allen Arthur Bag Implementation: Remove • As is often the case, remove is the most complex. Leaves a “hole”. What value should fill the hole?

  16. 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 private inner routines EleType leftmostChild (Node current) { … // return value of leftmost child of current } Struct Node * removeLeftmostChild (Node current) { … // return tree with leftmost child removed }

  17. Angela Alice Audrey Allen Arthur 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”

  18. Once more, separate root and node void BSTremove (struct BST * tree, EleType value) { if (BSTincludes(tree, value)) { tree->root = BSTnodeRemove (tree->root, value); tree->size--; } }

  19. Node Remove: easy if you return a tree Node remove (Node current, EleType 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

  20. Translate the previous into code struct BSTnodeRemove (struct node * current, EleType testValue) { if (EQ(testValue, current->value)) { /* found it! */ if (current->right == 0) return current->left; else { current->value = leftmostChild(current->right); current->right = removeLeftMost (current->right); } } else if (LT(testValue, current.value)) current->left = BSTnodeRemove (current->left, testValue) else current->right = BSTnoderemove (current->right, testValue) return current; }

  21. Little Helper Routines - get value of lmc EleType leftMostChild (struct node * current) { while (current->left != 0) current = current->left; return current->value; }

  22. Second helper routine - remove leftmost struct node * removeLeftMost (struct node * current) { if (current->left == 0) return current->right; else current->left = removeLeftMost (current->left); return current; }

  23. 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??

More Related