900 likes | 912 Views
Learn about optimal binary search trees through a detailed algorithm using probabilities and identifiers to compute optimal cost and roots.
E N D
10.1 Optimal Binary Search Trees Figure 10.1: Binary search tree corresponding to a binary search on the file (do, if, while)
10.1 Optimal Binary Search Trees(Cont’) Figure 10.2: Two binary search trees
10.1 Optimal Binary Search Trees(Cont’) Figure 10.3: Extended binary trees corresponding to search trees of Figure 10.2
10.1 Optimal Binary Search Trees(Cont’) Figure 10.4: Binary search trees with three identifiers
10.1 Optimal Binary Search Trees(Cont’) Figure 10.5: An optimal binary search tree Tij
10.1 Optimal Binary Search Trees(Cont’) Figure 10.6: Computation of c04 and r04. The computation is carried out by Row from row 0 to row 4
10.1 Optimal Binary Search Trees(Cont’) Figure 10.7: Optimal binary search tree for Example 10.2
10.1 Optimal Binary Search Trees(Cont’) template <class KeyType> BST<KeyType>::obst(int *p, int *q, Element<KeyType> *a, int n) // Given n distinct identifiers a1<a2<···<an, and probabilities pj, 1≤j≤n, and // qi, 0≤i≤n this algorithm computes the cost cij of optimal binary search trees Tij // for identifiers ai+1,···,aj. It also computes rij, the root of Tij. Wij is the weight of Tij. { for(int i=0; i<n; i++) { w[i][i] = q[i]; r[i][i] = c[i][i] = 0; // initialize w[i][i+1] = q[i] + q[i+1] + p[i+1]; // optimal trees with one node r[i][i+1] = i + 1; c[i][i+1] = w[i][i+1]; } w[n][n] = q[n]; r[n][n] = c[n][n] = 0;
10.1 Optimal Binary Search Trees(Cont’) for(int m=2; m<=n; m++) // find optimal trees with m nodes for(i=0; i<=n-m; i++) { int j = i + m; w[i][j] = w[i][j-1] + p[j] + q[j]; int k = KnuthMin(I,j); // KnuthMin returns a value k in the range [r,[i, j-1], r[i+1, j]] // minimizing c[I, k-1] + c[k, j] c[i][j] = w[i][j] + c[i][k-1] + c[k][j]; // Eq.(10.3) r[i][j] = k; } } // end of obst Program 10.1 : Finding an optimal binary search tree
10.2 AVL Trees Figure 10.8: Binary search tree obtained for the months of the year
10.2 AVL Trees(Cont’) Figure 10.9: A balanced tree for the months of the year
10.2 AVL Trees(Cont’) Figure 10.10: Degenerate binary search tree
10.2 AVL Trees(Cont’) Figure 10.11: Balanced trees obtained for the months of the year
10.2 AVL Trees(Cont’) Figure 10.12: Rebalancing rotations
10.2 AVL Trees(Cont’) template <class KeyType> Boolean AVL<KeyType>::Insert(const Element<KeyType>& x) // The identifier x is inserted into the AVL tree. AvlNode<KeyType> *a, *b, *c, *f, *p, *q, *y, *clchild, *crchild; Boolean Found, Unbalanced; int d; { if(!root) { // special case: empty tree y = new AvlNode<KeyType>; y -> data = x; root = y; root -> bf = 0; root -> LeftChild = root -> RightChild = 0; return TRUE; }
10.2 AVL Trees(Cont’) // phase 1: Locate insertion point for x. a keeps track of the most recent node with // balance factor ±1, and f is the parent of a. q follows p through the tree. f=0; a=p=root; q=0; Found=FALSE; while(p && !Found) { // search for insertion point for x if(p->bf) { a=p; f=q; } if(x.key < p->data.key) { q=p; p=p->LeftChild; } // take left branch else if(x.key > p->data.key) { q=p; p=p->RightChild; } else { y=p; Found=TRUE; } } // end of while
10.2 AVL Trees(Cont’) if(!Found) { // phase 1: Insert and rebalance. x is not in the tree and // may be inserted as the appropriate child of q. y = new AvlNode<KeyType>; y->data = x; y->LeftChild = y->RightChild = 0; y->bf = 0; if(x.key < q->data.key) q->LeftChild = y; // insert as left child else q->RightChild = y; // insert as right child // Adjust balance factors of nodes on path from a to q. Note that by the definition // of a, all nodes on this path must have balance factors of – and so will change to // ±1. d=+1 implies that x is inserted in the lift subtree of a. d = -1 implies // that x is inserted in the right subtree of a. if(x.key > a->data.key) { p = a->RightChild; b = p; d = -1; } else { p = a->LeftChild; b = p; d = 1; }
10.2 AVL Trees(Cont’) while(p!=y) if(x.key > p->data.key) { // height of right increases by 1 p->bf = -1; p = p->RightChild; } else { // height of left increases by 1 p->bf = 1; p = p->LeftChild; } Is tree unbalanced? Unbalanced = TRUE; if(!(a->bf) || !(a->bf + d)) { // tree still balanced a->bf += d; Unbalanced = FALSE; }
10.2 AVL Trees(Cont’) if(Unbalanced) { // tree unbalanced, determine rotation type if(d == 1) { // left imbalance if(b->bf == 1) { // rotation type LL a->LeftChild = b->RightCHild; b->RightChild = a; a->bf = 0; b->bf = 0; } else { // rotation type LR c = b->RightChild; b->RightChild = c->LeftChild; a->LeftChild = c->RightChild; c->LeftChild = b; c->RightChild = a; switch(c->bf) { case 1: // LR(b) a->bf = -1; b->bf = 0; break; case -1: // LR(c) b->bf = 1; a->bf = 0;
10.2 AVL Trees(Cont’) switch(c->bf) { case 1: // LR(b) a->bf = -1; b->bf = 0; break; case -1: // LR(c) b->bf = 1; a->bf = 0; break; case 0: // LR(a) b->bf = 0; a->bf = 0; break; } c->bf = 0; b = c; // b is the new root } // end of LR } // end of left imbalance else { // right imbalance: this is symmetric to left imbalance }
10.2 AVL Trees(Cont’) // Subtree with root b has been rebalanced and is the new subtree. if(!f) root = b; else if(a == f->LeftChild) f->LeftChild = b; else if(a == f->RightChild) f->RightChild = b; } // end of if Unbalanced return TRUE; } // end of if(!found) return FALSE; } // end of AVL::Insert Program 10.2 : Insertion into an AVL tree
10.2 AVL Trees(Cont’) Figure 10.13: Comparison of various structures
10.3 2-3 Trees 10.3.1 Definition and Properties • Definition A 2-3 tree is a search tree that either is empty or satisfies the following properties (1) Each internal node is a 2-node or a 3-node. A 2-node has one element; 3-node has two elements (2) Let LeftChild and MiddleChild denote the children of a 2-node. Let dataL be the element in this node, and let dataL.key be its key. All elements in the 2-3 subtree with root LeftChild have key less than dataL.key, whereas all elements in the 2-3 subtree with root MiddleChild have key greater than dataL.key
10.3 2-3 Trees(Cont’) (3) Let LeftChild, MiddleChild, and RightChild denote the children of 3-node. Let dataL and dataR be the two elements in this node. Then, dataL.key<dataR.Key; all keys in the 2-3 subtree with root LeftChild are less than dataL.key; all keys in the 2-3 subtree with root MiddleChild are less than dataR.key and greater than datL.key; and all keys in the 2-3 subtree with root RightChild are greater than dataR.key (4) All external nodes are at the same level
10.3 2-3 Trees(Cont’) Figure 10.14:Example of a 2-3 tree
10.3 2-3 Trees(Cont’) 10.3.2 Searching a 2-3 tree template <class KeyType> Two3Node<KeyType>* Two3<KeyType>::Search(const Element<KeyType>& x) //Search the 2-3 tree for an element x. If the element is not in the tree, then //return 0. Otherwise, return a pointer to the node that contains this element { for(Two3Node<KeyType> *p=root;p;) switch(p->compare(x)) { case 1: p=p->LeftChild; break; case 2: p=p->MiddleChild; break; case 3: p=p->RightChild; break; case 4: return p; //x is one of the keys in p } //end of switch and for } //end of Search Analysis : O(log n) Program 10.3:Searching a 2-3 tree
10.3 2-3 Trees(Cont’) 10.3.3 Insertion into a 2-3 tree Figure 10.15:Insertion into the 2-3 tree of Figure 10.14
10.3 2-3 Trees(Cont’) Figure 10.16:Insertion of 60 into the 2-3 tree of Figure 10.15(b)
10.3 2-3 Trees(Cont’) • Algorithm of the Insertion (1) void Two3::NewRoot(const Element& x, Two3Node *a) • be invoked when the root of the 2-3 tree is to change • The Single element x is inserted into the new root, while a is made its MiddleChild • The old root becomes the LeftChild of the new root
10.3 2-3 Trees(Cont’) (2) Two3Node* Two3::FindNode(const Element& x) • be a modified version of Two3::Search (Program 10.3) • searches a nonempty 2-3 tree for the presence of an element with key x.key • If this key is present, then it returns 0. Otherwise, it returns a pointer to the leaf node encountered in th search (3) void InsertionError() • When an attempt to insert an element whose key corresponds to that of an element already in the 2-3 tree is made, an insertion Error occurs • This function signals an error
10.3 2-3 Trees(Cont’) (3) void Two3Node::PutIn(const Element& x, TwoNode *a) • Be used to insert an element x into a node (this) that has exactly one element in it • The subtree a is to be placed immediately to the right of x • if x becomes dataL, then a becomes MiddleChild, and the previous values of dataL and MiddleChild move to dataR and Rightchild, respectively, • If x becomes dataR, then a becomes RightChild
10.3 2-3 Trees(Cont’) (5) Element& Two3::Split(Two3Node* p, Element& x, Two3Node *olda, Two3Node *a) • operates on a Two3Node (p) that initially contains two elements as follows • The newly created, empty node pointed at by a will contain the element with the largest key from among the two elements initially in p and the element x
10.3 2-3 Trees(Cont’) • Analysis : O(log n) Template <class KeyType> Boolean Two3<KeyType>::Insert(const Element<KeyType>& y) //Insert the element y into the 2-3 tree only if it does not already contain //an element with the same key. { Two3Node<KeyType> *p; Element<KeyType> x=y; if(x.key>=MAXKEY) return FALSE; //invalid key if(!root){ NewRoot(x, 0); return TRUE; } //empty 2-3 tree if(!(p=FindNode(x))) { InsertionError(); return FALSE; } //key already in 2-3 tree for(Two3Node<KeyType> *a=0; ; )
10.3 2-3 Trees(Cont’) if(p->dataR,key == MAXKEY) { //p is a 2-node p->PutIn(x, a); return TRUE; } else { //p is a 3-node Two3Node<KeyType> *olda=a; a=new(Two3Node<KeyType>); x=Split(p, x, olda, a); if(root==p) { //root has been split NewRoot(x, a); return TRUE; } else p=p->parent(); } //end of p is a 3-node and for loop } //end of Insert Program 10.4: Insertion into a 2-3 tree
10.3 2-3 Trees(Cont’) 10.3.4 Deletion from a 2-3 tree Figure 10.17: Deletion from a 2-3 tree(continued on next page)
10.3 2-3 Trees(Cont’) Figure 10.17: Deletion from a 2-3 tree
10.3 2-3 Trees(Cont’) • Algorithm of Deletion Step1 : Modify node p as necessary to reflect its status after the desired element has been deleted Step2 : for(;p has zero elements && p !=root; p=r) { let r be the parent of p, and let q be the left or right sibling of p (as appropriate) if(q is a 3-node) perform a rotation else perform a combine; } Step3 : If p has zero elements, then p must be the root. The left child of p becomes the new root, and node p is deleted Program 10.5: Step in deletion from a leaf of a 2-3 tree
10.4 2-3-4 Trees Figure 10.20: Example of a 2-3-4 tree
10.4 2-3-4 Trees(Cont’) Figure 10.21: Transformation when the 4-node is the root
10.4 2-3-4 Trees(Cont’) Figure 10.22: Transformation when the 4-node is the child of a 2-node
10.4 2-3-4 Trees(Cont’) Figure 10.23: Transformation when the 4-node is the lift child of a 3-node
10.4 2-3-4 Trees(Cont’) Figure 10.24: Transformation when the 4-node is the lift middle child of a 3-node
10.4 2-3-4 Trees(Cont’) template <class KeyType> Boolean Two34<KeyType>::Insert(const Element<KeyType>& y) // Insert element y into the 2-3-4 tree. { if(y.key >= MAXKEY) return FALSE; if(!root) { NewRoot(y); return TRUE; } // insertion into an empty 2-3-4 tree if(FourNode(root)) SplitRoot(); for(Two34Node<KeyType> *p = root, * q = 0 ; ;) // q is parent of p if(FourNode(p)) { if(NodeType(q) == TwoNode) SplitChildOf2(p, q); else SplitChildOf3(p, q); p = q; // back up to parent for next comparison }
10.4 2-3-4 Trees(Cont’) q = p; switch(p->compare(y)) { case equal: InsertionError(); return FALSE; // key is duplicated case leaf: p->PutIn(y); return TRUE; case lChild: p = p->LeftChild; break case lmChild: p = p->LeftMidChild; break; case rmChild: p = p->RightMidCHild; break; case rChild: p = p->RightChild; break; } // end of switch } // end of for } // end of Insert Program 10.9 : Insertion into a 2-3-4 tree