320 likes | 328 Views
CS 3013. Binary Search Trees. Definition of a Tree. A Binary tree is a set T of nodes such that either 1. T is empty or 2. T is partitioned into three disjoint subsets. A single node r, the root Two (possibly empty) sets that are binary trees, called left and right subtrees of r. T.
E N D
CS 3013 Binary Search Trees
Definition of a Tree A Binary tree is a set T of nodes such that either 1. T is empty or 2. T is partitioned into three disjoint subsets. A single node r, the root Two (possibly empty) sets that are binary trees, called left and right subtrees of r. T T T Tl Tr
Structure of a Tree root struct Node{ int value; Node * left; Node * right; } 5 class Tree{ Node * _root; public: Tree();//constructor Insert(int); Print(); } 4 6 3 10 7 9
Binary Search Trees • Binary Search Trees (BSTs) are an important data structure for manipulating dynamically changing data sets. • Each node has the following fields: • value: an identifying field inducing a total ordering • left: pointer to a left child (may be NULL) • right: pointer to a right child (may be NULL) • p: (sometimes) pointer to a parent node (NULL for root)
F B H A D K Binary Search Trees • BST property: Value of nodes in left subtree <= roots value Value of nodes in right subtree > roots value • Example:
Inorder Tree Walk • What does the following code do? void TreeWalk(Node * tree){ if(tree!=nullptr){ TreeWalk(tree->left); cout<<tree->value<<endl; TreeWalk(tree->right); }} • A: prints elements in sorted (increasing) order • This is called an inorder tree walk • Preorder tree walk: print root, then left, then right • Postorder tree walk: print left, then right, then root
F B H A D K Inorder Tree Walk • Example: • How long will a tree walk take? • Prove that inorder walk prints in monotonically increasing order
Operations on BSTs: Search • Given a key and a pointer to a node, returns an element with that key or nullptr. This should be private. Why? Node * TreeSearch(Node * ptr, int k){ if (ptr == nullptr)return nullptr; if (ptr->value==k) return ptr; if (k < ptr->value) return TreeSearch(ptr->left, k); else return TreeSearch(ptr->right, k); }
F B H A D K BST Search: Example • Search for D and C:
Operations of BSTs: Insert For a non recursive insert • Adds an element x to the tree so that the binary search tree property continues to hold • The basic algorithm • Like the search procedure above • Insert x in place of nullptr • Use a “trailing pointer” to keep track of where you came from (like inserting into singly linked list)
F B H A D K BST Insert: Example • Example: Insert C C
BST class BST class { Node * _tree; InsertAux(Node* & , constint & ) public: BST(){ _root=nullptr;} ~BST(); // Destructor Insert(int v){InsertAux(_root,v);} }
Aux Method’s • if a method returns a pointer into the tree then the method cannot be public • in this case you need to have two methods • one public and one private. • the public one calls the private method • In main you are only allowed to call the public version.
Recursive Insert in a Class void BST::InsertAux(Node* & tree, const int & item) { if(tree==nullptr) tree=new Node(item); else if (item < tree->value) InsertAux(tree->left, item); else InsertAux(tree->right, item); } Note &’s
What happens when you insert the numbers 1,2,3,…,10 into a BST in that order? you insert the numbers 10.9,…,1 into a BST in that order? Insert these numbers in a BST 5,7,3,1,8,2,6,4 Draw it.
BST Search/Insert: Running Time • What is the running time of TreeSearch() or insertAux()? • A: O(h), where h = height of tree • What is the height of a binary search tree? • A: worst case: h = O(n) when tree is just a linear string of left or right children • We’ll keep all analysis in terms of h for now • Later we’ll see how to maintain h = O(lg n)
BST Destroy the tree BST::~BST(){destroyTree(_root)} void BST::destroyTree(Node *& tree) { if (tree != nullptr;) { destroyTree(tree->left); destroyTree(tree->right); delete tree; tree=nullptr; } }
F Example: delete Kor H or B B H C A D K BST Operations: Delete • Deletion is a bit tricky • 3 cases: • x has no children: • Remove x • x has one child: • Splice out x • x has two children: • Swap the value of x with successor (or predecessor) • Perform case 1 or 2 to delete it
Delete Algorithm void BST::TreeDelete(Node *& root, int x) { if(root!=nullptr){ Node * tempPtr; Node * predPtr; if(x<root->val)TreeDelete(root->left, x); else if(x>root->val)TreeDelete(root->right, x); else { // we have found it so lets delete it // tree points at it right!? // If No children we just delete it if(root->left==nullptr && root->right==NULL){ delete(root); root=nullptr; // what happens when we return; // return here! important! }
Delete Continued with one child // Check to see if the node to delete has only one child if(root->left==nullptr){ // Then splice in the right side tempPtr=root->right; delete root; root=tempPtr; }else if (root->right==NULL){ // splice left tempPtr=root->left; delete(root); root=tempPtr; } else // both children exist! so...
Delete Continued with two children // Here root has two children // We first find the successor { tempPtr=root->right; // Go right // and the all the way to the left while(tempPtr->left!=nullptr){ predPtr=tempPtr; tempPtr=tempPtr->left; } root->val=tempPtr->val; // Copy the value up to the root if(root->right==tempPtr)root->right=tempPtr->right; else predPtr->left=tempPtr->right; delete tempPtr; } root predPtr tempPtr
BST Operations: Delete • Why will case 2 always go to case 0 or case 1? • A: because when x has 2 children, its successor is the minimum in its right subtree • Could we swap x with predecessor instead of successor? • A: yes. Would it be a good idea? • A:See the Eppinger paper!!
Sorting With Binary Search Trees • Informal code for sorting array A of length n: BSTSort(A) BST t; for(auto v:A) t.TreeInsert(v); t.InorderTreeWalk(root);// prints • What will be the running time in the • Worst case? • Average case?
F B H C A D K Left Child Right Sibling Representation F B H A D H C RCLS format Normal format Really is a binary way to represent an n ary tree. Also each child has a pointer to its parent.
Recursive Traversal of a LCRS Tree F LCRST::Traverse(Node * t) { if (t != nullptr) then Traverse(t->child()) If (t->sibling() !=nullptr) then Traverse(t->sibling()) } B H A D H C Here t->child() returns a pointer to the left child and t->sibling() returns a ptr to right child
Algorithm BT->LCRS Format Can you design an algorithm that will convert a binary tree to the left child right sibling format?
Saving a binary search tree in a file • We can do this so the tree gets restored to the original shape. How do we do this? save in preorder ! • Or we can restore it in a balanced shape save in inorder and ?
Loading a balanced tree froma sorted list readTree(Node *& treePtr,int n) { if (n>0) { // read in the left subtree treePtr=new Node(nullptr,nullptr); readTree(treePtr->left,n/2); cin>> treePtr->val; // read in the right subtree readTree(treePtr->right,(n-1)/2); }
F B H A D K Level Order Traversal How do you perform an level by level traversal? Q.enq(root) While(Q not empty){ x = Q.deq(); Print x; Q.enq(left_child); Q.enq(right_child); } NOTE: This uses aqueue as its support data structure
Expression Trees + * + + X 3 Y W 5 W + 5 * X + 3 + Y inorder traversal ((W+5)*X + (3+Y)) with parens How about preorder and postorder traversals?
Problem A preorder traversal of a binary tree produced ADFGHKLPQRWZ and an inorder traversal produced GFHKDLAWRQPZ Draw the binary tree.
Program to Build Tree void BuildTree(string in,string post) { char root; int len=in.length(); // NOTE: Last char of postorder traveral is the root of the tree if(len==0)return; root=post[len-1]; cout<<root; // print the root // Search for root in the inorder traversal list int i=0; while(in[i]!=root)i++; // skip to the root // i now points to the root in the inorder traversal // The chars from 0 to i-1 are in the left subtree and // the chars from i+1 to len_in-1 are in the right sub tree. // Process left sub tree BuildTree(in.substr(0,i),post.substr(0,i)); //Process right sub tree BuildTree(in.substr(i+1,len-i-1), post.substr(i,len-i-1)); } 0 1 2 . . . substr(start, len)