AVL TREES First we develop a class AVLNode for the nodes in an AVL tree. The code is given below and in the file avlnode.h. template
class AVLNode { friend AVLtree<E,K>; public: AVLNode() {LeftChild = RightChild = 0;} AVLNode(const E& e) {data = e; bf = 0; LeftChild = RightChild = 0;} private: E data; int bf;
// balance factor
AVLNode<E,K> *LeftChild,
// left subtree
*RightChild; // right subtree }; The interface for the class AVLtree is given below and in the file avl.h. template class AVLtree {
public: AVLtree() {root = 0;} ~AVLtree() {Erase(root);} bool Search(const K& k, E& e) const; AVLtree<E,K>& Insert(const E& e); AVLtree<E,K>& Delete(const K& k, E& e); void Ascend() {
InOutput(root); cout << endl;
} protected: AVLNode<E,K> *root;
// root node
void Erase(AVLNode<E,K> *t); void InOutput(AVLNode<E,K> *t); void FixBF(AVLNode<E,K> *,AVLNode<E,K>*, const E&); 1
void RRrotate(AVLNode<E,K> *,AVLNode<E,K>*, AVLNode<E,K> *); void LLrotate(AVLNode<E,K> *,AVLNode<E,K>*, AVLNode<E,K> *); void RLrotate(AVLNode<E,K> *,AVLNode<E,K>*, AVLNode<E,K> *); void LRrotate(AVLNode<E,K> *,AVLNode<E,K>*, AVLNode<E,K> *); }; Erase template void AVLtree<E,K>::Erase(AVLNode<E,K> *t) {// Delete all nodes in AVL tree with root t. // Use a postorder traversal. if (t) {
Erase(t->LeftChild); Erase(t->RightChild); delete t;
} }
Search template bool AVLtree<E,K>::Search(const K& k, E &e) const {// Search for element that matches k. // pointer p starts at the root and moves through // the tree looking for an element with key k AVLNode<E,K> *p = root; while (p) // examine p->data if (k < p->data) p = p->LeftChild;
2
else if (k > p->data) p = p->RightChild; else {// found element e = p->data; return true; } return false; } Fix Balance Factor template void AVLtree<E,K>::FixBF(AVLNode<E,K> *q, AVLNode<E,K> *r, const E &e) {
// Balance factors from q to r were originally 0. //They need to be changed to +1or-1. //Use e to find path from q to r. while (q != r) if (e < q->data) {
// height of left subtree has increased q->bf = 1; q = q->LeftChild;
} else {
// height of right subtree has increased q->bf = -1; q = q->RightChild;
} }
The elements can be output in ascending order by performing an inorder traversal as below. template void AVLtree<E,K>::InOutput(AVLNode<E,K> *t) 3
{
// Output in ascending order. // Use an inorder traversal. if (t) {
InOutput(t->LeftChild); cout << t->data << " "; InOutput(t->RightChild);
} }
Rotations template void AVLtree<E,K>::LLrotate(AVLNode<E,K> *PA, AVLNode<E,K> *A, AVLNode<E,K> *B) {
// LL rotation around A.
PA is parent of A
// and B left child of A. // restructure subtree at A A->LeftChild = B->RightChild; B->RightChild = A; if (PA) // A is not the root if (A == PA->LeftChild) PA->LeftChild = B; else PA->RightChild = B; else root = B;
4
// set balance factors A->bf = B->bf = 0; } template void AVLtree<E,K>::RRrotate(AVLNode<E,K> *PA, AVLNode<E,K> *A, AVLNode<E,K> *B) {
// RR rotation around A.
PA is parent of A
// and B right child of A. // restructure subtree at A A->RightChild = B->LeftChild; B->LeftChild = A; if (PA) // A is not the root if (A == PA->LeftChild) PA->LeftChild = B; else PA->RightChild = B; else root = B; // set balance factors A->bf = B->bf = 0; } template void AVLtree<E,K>::LRrotate(AVLNode<E,K> *PA, AVLNode<E,K> *A, AVLNode<E,K> *B) {
// LR rotation around A.
PA is parent of A
// and B left child of A. AVLNode<E,K> *C = B->RightChild; 5
// restructure subtree at A A->LeftChild = C->RightChild; B->RightChild = C->LeftChild; C->LeftChild = B; C->RightChild = A; if (PA) // A is not the root if (A == PA->LeftChild) PA->LeftChild = C; else PA->RightChild = C; else root = C; // set balance factors int b = C->bf; if (b == 1) {
B->bf = 0;
A->bf = -1;
} else if (b) {
B->bf = 1;
A->bf = 0;
} else // b = 0 B->bf = A->bf = 0; C->bf = 0; } template 6
void AVLtree<E,K>::RLrotate(AVLNode<E,K> *PA, AVLNode<E,K> *A, AVLNode<E,K> *B) {
// RL rotation around A.
PA is parent of A
// and B left child of A. AVLNode<E,K> *C = B->LeftChild; // restructure subtree at A A->RightChild = C->LeftChild; B->LeftChild = C->RightChild; C->LeftChild = A; C->RightChild = B; if (PA) // A is not the root if (A == PA->LeftChild) PA->LeftChild = C; else PA->RightChild = C; else root = C; // set balance factors int b = C->bf; if (b == 1) {
B->bf = -1;
A->bf = 0;
} else if (b) {
B->bf = 0;
A->bf = 1;
} 7
else // b = 0 B->bf = A->bf = 0; C->bf = 0; }
Insertion template AVLtree<E,K>& AVLtree<E,K>::Insert(const E& e) {
// Insert e if not duplicate. AVLNode<E,K> *p = root,
// search pointer
*pp = 0,
// parent of p
*A = 0,
// node with bf != 0
*PA;
// parent of A
// find place to insert // also record most recent node with bf != 0 // in A and its parent in PA while (p) {
// examine p->data if (p->bf) {
// new candidate for A node A = p; PA = pp;
} pp = p; 8
// move p to a child if (e < p->data) p = p->LeftChild; else if (e > p->data) p = p->RightChild; else throw BadInput(); // duplicate }
// get a node for e and attach to pp AVLNode<E,K> *r = new AVLNode<E,K> (e); if (root) {
// tree not empty if (e < pp->data) pp->LeftChild = r; else pp->RightChild = r;
} else {
// insertion into empty tree root = r; return *this; }
// see if we must rebalance or simply change balance factors if (A) // possible rebalancing needed {
if (A->bf < 0) // bf = -1 before insertion {
if (e < A->data) {
// insertion in left subtree // height of left subtree has increased by 1 // new bf of A is 0, no rebalancing 9
A->bf = 0; // fix bf on path from A to r FixBF(A->LeftChild,r,e); } else {
// insertion in right subtree // bf of A is -2, rebalance AVLNode<E,K> *B = A->RightChild; if (e > B->data) {
// RR case FixBF(B->RightChild,r,e); RRrotate(PA,A,B);
} else {
// RL case FixBF(B->LeftChild,r,e); RLrotate(PA,A,B);
} } } else {
// bf = +1 before insertion
if (e > A->data) {
// insertion in right subtree // height of right subtree has increased by 1 // new bf of A is 0, no rebalancing A->bf = 0; // fix bf on path from A to r FixBF(A->RightChild,r,e);
} else {
// insertion in left subtree // bf of A is +2, rebalance 10
AVLNode<E,K> *B = A->LeftChild; if (e < B->data) {
// LL case FixBF(B->LeftChild,r,e); LLrotate(PA,A,B);
} else {
// LR case FixBF(B->RightChild,r,e); LRrotate(PA,A,B);
} } } } else // A is NULL, no rebalancing FixBF(root,r,e); return *this; }
Deletion template AVLtree<E,K>& AVLtree<E,K>::Delete(const K& k, E& e) {
// Delete element with key k and put it in e. // Throw BadInput exception if there is no element // with key k. Stack*> S(100); 11
// set p to point to node with key k AVLNode<E,K> *p = root; // search pointer while (p && p->data != k) {
// move to a child of p S.Add(p); if (k < p->data) p = p->LeftChild; else p = p->RightChild;
} if (!p) throw BadInput(); // no element with key k e = p->data;
// save element to delete
// restructure tree // handle case when p has two children if (p->LeftChild && p->RightChild) {
// two children // convert to zero or one child case // find largest element in left subtree of p S.Add(p); AVLNode<E,K> *s = p->LeftChild; while (s->RightChild) {
// move to larger element S.Add(s); s = s->RightChild;
} 12
// move largest from s to p p->data = s->data; p = s; } // p has at most one child
// save child pointer in c
AVLNode<E,K> *c; if (p->LeftChild) c = p->LeftChild; else c = p->RightChild; // delete p if (p == root) root = c; else {
// is p a left or right child? if (p == S.Top()->LeftChild) S.Top()->LeftChild = c; else S.Top()->RightChild = c; }
E f = p->data; // f may not equal e delete p; // rebalance tree & correct BF, use stack to retrace path to root // set q to parent of deleted node AVLNode<E,K> *q; try {
S.Delete(q); 13
} catch (OutOfBounds) {
return *this;
// root was deleted
} while (q) { if (f <= q->data) {
// deleted from left subtree of q // height of left subtree reduced by 1 q->bf--; if (q->bf == -1) // height of q is unchanged return *this; if (q->bf == -2) {
// q is unbalanced // classify imbalance and rotate AVLNode<E,K> *B = q->RightChild,*PA; // q is A node, PA is parent of A try {
S.Delete(PA);
} catch (OutOfBounds) {
PA = 0;
// A is root
} switch (B->bf) { case 0:
// L0 imbalance
RRrotate(PA,q,B); B->bf = 1; q->bf = -1;
// q is A node
return *this; case 1:
// L1 imbalance
RLrotate(PA,q,B); break; case -1:
// must continue on path to root // L-1 imbalance 14
RRrotate(PA,q,B); } q = PA; } else {
// q->bf is 0 try {
S.Delete(q);
} catch (OutOfBounds) {
return *this;
} } } else {
// f > q->data // deleted from right subtree of q // height of right subtree reduced by 1 q->bf++; if (q->bf == 1) // height of q is unchanged return *this; if (q->bf == 2) {
// q is unbalanced,classify imbalance and rotate AVLNode<E,K> *B = q->LeftChild,*PA; // q is A node,PA is parent of A try {
S.Delete(PA);
} catch (OutOfBounds) { }
PA = 0; // A is root
switch (B->bf) { case 0:
// R0 imbalance 15
LLrotate(PA,q,B); B->bf = -1; q->bf = 1;
// q is A node
return *this; case 1:
// R1 imbalance
LLrotate(PA,q,B); break; case -1:
// must continue on path to root // R-1 imbalance
LRrotate(PA,q,B); } q = PA; } else {
// q->bf is 0 try {
S.Delete(q);
} catch (OutOfBounds) {
return *this;
} } } } return *this; }
16