头文件:
/***************************************************************************** * avltree.h * * AVL Tree implemented by C++ class template. * * This class provides "traversal(preorder,inorder or postorder), "search", * "insert" and "remove" operations by using an AVL Tree. The rotation * technology is used to keep the tree balanced. Of cause, you can get the * height of the tree by the subroutine "height". * * Zhang Ming, 2009-10 *****************************************************************************/ #ifndef AVLTREE_H #define AVLTREE_H #include <cstdlib> #include <stack.h> namespace itlab { /** * Node in AVL Tree */ template <typename Object, typename Key> struct AVLNode { Object data; int balance; AVLNode<Object, Key> *left, *right; AVLNode() : left(NULL), right(NULL), balance(0) { } AVLNode( const Object &x, AVLNode<Object, Key> *lp=NULL, AVLNode<Object, Key> *rp=NULL ) : balance(0) { data = x; left = lp; right = rp; } bool operator<( AVLNode<Object, Key> &t ) { return data < t.data; } bool operator>( AVLNode<Object, Key> &t ) { return data > t.data; } bool operator==( AVLNode<Object, Key> &t ) { return data == t.data; } }; // class AVLNode /** * AVL Tree */ template <typename Object, typename Key> class AVLTree { public: AVLTree(); ~AVLTree(); // AVLTree( const AVLTree<Object, Type> &rhs ); // AVLTree<Object, Type>& operator=( const AVLTree<Object, Type> &rhs ); inline bool isEmpty() const; inline void makeEmpty(); inline void print( const string &mode ); inline int height() const; inline AVLNode<Object, Key>* search( Key k ); inline bool insert( Object &x ); inline bool remove( Key k, Object &x ); private: AVLNode<Object, Key> *root; void preTraversal( AVLNode<Object, Key> *t ); void inTraversal( AVLNode<Object, Key> *t ); void postTraversal( AVLNode<Object, Key> *t ); void makeEmpty( AVLNode<Object, Key> * &t ); int height( AVLNode<Object, Key> *t ) const; AVLNode<Object, Key>* search( Key k, AVLNode<Object, Key> *t ); bool insert( AVLNode<Object, Key> * &ptr, Object &x ); bool remove( AVLNode<Object, Key> * &ptr, Key k, Object &x ); void rotateL( AVLNode<Object, Key> * &ptr ); void rotateR( AVLNode<Object, Key> * &ptr ); void rotateLR( AVLNode<Object, Key> * &ptr ); void rotateRL( AVLNode<Object, Key> * &ptr ); void handleUnderflow(); }; // class AVLTree #include <avltree-impl.h> } // namespace itlab #endif // AVLTREE_H
实现文件:
/***************************************************************************** * abltree-impl.h * * Implementation for AVLTree class. * * Zhang Ming, 2009-10 *****************************************************************************/ /** * constructors and destructor */ template <typename Object, typename Key> AVLTree<Object, Key>::AVLTree() : root(NULL) { } template <typename Object, typename Key> AVLTree<Object, Key>::~AVLTree() { delete root; } /** * If the tree is empty, return true. */ template <typename Object, typename Key> inline bool AVLTree<Object, Key>::isEmpty() const { return ( root == NULL ); } /** * Make the tree empty. */ template <typename Object, typename Key> inline void AVLTree<Object, Key>::makeEmpty() { makeEmpty( root ); } /** * Traverse the tree, the order is specified by parameter * "mode", which can be "preorder", "inorder" or "postorder". */ template <typename Object, typename Key> inline void AVLTree<Object, Key>::print( const string &mode ) { if( isEmpty() ) cout << "The tree is empty!" << endl; else { if( mode == "preorder" ) preTraversal( root ); else if( mode == "inorder" ) inTraversal( root ); else if( mode == "postorder" ) postTraversal( root ); else cout << "Invalid travesal method!" << endl; } } /** * Return the high of the tree. */ template <typename Object, typename Key> inline int AVLTree<Object, Key>::height() const { return height( root ); } /** * Searching a node with key "k" and then return a pointer * pointed to it. */ template <typename Object, typename Key> inline AVLNode<Object, Key>* AVLTree<Object, Key>::search( Key k ) { if( !isEmpty() ) return search( k, root ); else { handleUnderflow(); return NULL; } } /** * Inserting an element into the tree. */ template <typename Object, typename Key> inline bool AVLTree<Object, Key>::insert( Object &x ) { return insert( root, x ); } /** * Removing an element with key "k" and then assign it to "x". */ template <typename Object, typename Key> inline bool AVLTree<Object, Key>::remove( Key k, Object &x ) { if( !isEmpty() ) return remove( root, k, x ); else { handleUnderflow(); return false; } } /** * Make the tree empty. */ template <typename Object, typename Key> void AVLTree<Object, Key>::makeEmpty( AVLNode<Object, Key> * &t ) { if( t != NULL ) { makeEmpty( t->left ); makeEmpty( t->right ); delete t; } t = NULL; } /** * preorder traversal */ template <typename Object, typename Key> void AVLTree<Object, Key>::preTraversal( AVLNode<Object, Key> *t ) { if( t != NULL ) { cout << " " << t->balance << "\t" << t->data; preTraversal( t->left ); preTraversal( t->right ); } }; /** * inorder traversal */ template <typename Object, typename Key> void AVLTree<Object, Key>::inTraversal( AVLNode<Object, Key> *t ) { if( t != NULL ) { inTraversal( t->left ); cout << " " << t->data; inTraversal( t->right ); } }; /** * postorder traversal */ template <typename Object, typename Key> void AVLTree<Object, Key>::postTraversal( AVLNode<Object, Key> *t ) { if( t != NULL ) { postTraversal( t->left ); postTraversal( t->right ); cout << " " << t->data; } }; /** * Compute the high of the subtree with root of "t". */ template <typename Object, typename Key> int AVLTree<Object, Key>::height( AVLNode<Object, Key> *t ) const { if( !t ) return -1; int heightL = height( t->left ); int heightR = height( t->right ); return ( heightL < heightR ) ? heightR+1 : heightL+1; } /** * Finding an element with key value of "k" in the * subtree with root of "t". */ template <typename Object, typename Key> AVLNode<Object, Key>* AVLTree<Object, Key>::search( Key k, AVLNode<Object, Key> *t ) { if( t == NULL ) return NULL; if( k == t->data.key ) return t; else if( k < t->data.key ) return search( k, t->left ); else return search( k, t->right ); } /** * Insert a new element x in the tree "t". * If "x" isn't existent, return "true", else return "false". */ template <typename Object, typename Key> bool AVLTree<Object, Key>::insert( AVLNode<Object, Key> * &t, Object &x ) { int flag; // flag for sigle or double rotation AVLNode<Object, Key> *child = t, *parent = NULL, *grandpa = NULL; Stack< AVLNode<Object, Key> * > st; // find the inserting position while( child != NULL ) { if( x == child->data ) return false; parent = child; st.push( parent ); if( x < parent->data ) child = parent->left; else child = parent->right; } child = new AVLNode<Object, Key>( x ); if( child == NULL ) { cerr << "Out of memory!" << endl; exit( 1 ); } // The tree is empty, the new element is the root of the tree. if( parent == NULL ) { t = child; return true; } if( x < parent->data ) parent->left = child; else parent->right = child; // equalization while( !st.isEmpty() ) { st.pop( parent ); // Modify the balance factor of node "parent". if( child == parent->left ) parent->balance--; else parent->balance++; // have equalized if( parent->balance == 0 ) { break; } // Current node is balance, but need backtracking upward. else if( parent->balance == 1 || parent->balance == -1 ) { child = parent; } // Current node is unbalance, doing equalization. else { flag = ( parent->balance < 0 ) ? -1 : 1; // Current node and its parent have the same balance // factor, so making sigle rotation. if( child->balance == flag ) { if( flag == -1 ) rotateR( parent ); else rotateL( parent ); } // Current node and its parent have the opposite balance // factor, so making double rotation. else { if( flag == -1 ) rotateLR( parent ); else rotateRL( parent ); } // Over the equalization. break; } } // The equalized node is the root of the tree. if( st.isEmpty() ) { t = parent; } // The equalized node is at the middle of the tree. else { st.getTop( grandpa ); if( grandpa->data > parent->data ) grandpa->left = parent; else grandpa->right = parent; } return true; }; /** * Delete the element x, which key is "k", in the tree "t". * If such key is existent, copy the deleted element to "x", * and return "true"; else return "false". */ template <typename Object, typename Key> bool AVLTree<Object, Key>::remove( AVLNode<Object, Key> * &t, Key k, Object &x ) { int flag = 0; // 1 : right subtree higher than left subtre // -1 : left subtree higher than right subtre int leftRight = 0; // 1 : right subtree; -1 : left subtree AVLNode<Object, Key> *current = t, *parent = NULL, *grandpa = NULL, *child = NULL; Stack< AVLNode<Object, Key> * > st; // Finding the deleted position. while( current != NULL ) { if( k == current->data.key ) { x = current->data; break; } parent = current; st.push( parent ); if( k < parent->data.key ) current = parent->left; else current = parent->right; } // No such node in the tree, deletion false. if( current == NULL ) return false; // The deleted node has tow children. if( ( current->left != NULL ) && ( current->right != NULL) ) { parent = current; st.push( parent ); // Find the immediate predecessor of "current" pointing // node in its left subtree. child = current->left; while( child->right != NULL ) { parent = child; st.push( parent ); child = parent->right; } // Copy "child" to "current", and the deleted node have // translated into the new node "child". current->data = child->data; current = child; } // The deleted node has no more than one child. if( current->left != NULL ) child = current->left; else child = current->right; // The deleted node is the root. if( parent == NULL ) { t = child; } // The deleted node is leaf or has only on child. else { // relinking if( parent->left == current ) parent->left = child; else parent->right = child; // equalization while( !st.isEmpty() ) { st.pop( parent ); // Modify the balance factor of "parent" node. if( parent->right == child ) parent->balance--; else parent->balance++; // The stack is empty, so do not need link upward // after rotation. if( st.isEmpty() ) { leftRight = 0; } // The stack isn't empty, so need link upward after rotation. else { st.getTop( grandpa ); leftRight = ( grandpa->left == parent ) ? -1 : 1; } // The balance of the node pointed by "parent" is 0, // so do not need modifying after deletion. if( parent->balance == 1 || parent->balance == -1 ) break; // The node pointed by "parent" is unbalance. if( parent->balance != 0 ) { // "child" pointing the higher subtree. if( parent->balance < 0) { flag = -1; child = parent->left; } else { flag = 1; child = parent->right; } // The left and right subtree of the higher subtree have // the same height. if( child->balance == 0 ) { // The higher subtree is the left subtree of "parent". if( flag == -1 ) { rotateR( parent ); parent->balance = 1; parent->right->balance = -1; } // The higher subtree is the right subtree of "parent". else { rotateL( parent ); parent->balance = -1; parent->left->balance = 1; } break; } // The higher subtree have the same balance factor // of its parent, so need sigle rotation. if( child->balance == flag ) { if( flag == -1 ) rotateR( parent ); else rotateL( parent ); } // The higher subtree have the opposite balance factor // of its parent, so need double rotation. else { if( flag == -1 ) rotateLR( parent ); else rotateRL( parent ); } // Linking upward after rotatin. if( leftRight == -1 ) grandpa->left = parent; else if( leftRight == 1 ) grandpa->right = parent; } // backtracking upward child = parent; } // Have modified to the root. if( st.isEmpty() ) t = parent; } delete current; return true; }; /** * Making left sigle rotation fo node pointed by "t", * and the root of the rotated tree is still pointed by "t". */ template <typename Object, typename Key> void AVLTree<Object, Key>::rotateL( AVLNode<Object, Key> * &t ) { AVLNode<Object, Key> *leftChild = t; t = leftChild->right; leftChild->right = t->left; t->left = leftChild; t->balance = leftChild->balance = 0; }; /** * Making right sigle rotation fo node pointed by "t", * and the root of the rotated tree is still pointed by "t". */ template <typename Object, typename Key> void AVLTree<Object, Key>::rotateR( AVLNode<Object, Key> * &t ) { AVLNode<Object, Key> *rightChild = t; t = rightChild->left; rightChild->left = t->right; t->right = rightChild; t->balance = rightChild->balance = 0; }; /** * Making left-right double rotation fo node pointed by "t", * and the root of the rotated tree is still pointed by "t". */ template <typename Object, typename Key> void AVLTree<Object, Key>::rotateLR( AVLNode<Object, Key> * &t) { AVLNode<Object, Key> *rightChild = t; AVLNode<Object, Key> *leftChild = rightChild->left; t = leftChild->right; leftChild->right = t->left; t->left = leftChild; if( t->balance <= 0 ) leftChild->balance = 0; else leftChild->balance = -1; rightChild->left = t->right; t->right = rightChild; if( t->balance == -1 ) rightChild->balance = 1; else rightChild->balance = 0; t->balance = 0; }; /** * Making right-left double rotation fo node pointed by "t", * and the root of the rotated tree is still pointed by "t". */ template <typename Object, typename Key> void AVLTree<Object, Key>::rotateRL( AVLNode<Object, Key> * &t ) { AVLNode<Object, Key> *leftChild = t; AVLNode<Object, Key> *rightChild = leftChild->right; t = rightChild->left; rightChild->left = t->right; t->right = rightChild; if( t->balance >= 0 ) rightChild->balance = 0; else rightChild->balance = 1; leftChild->right = t->left; t->left = leftChild; if( t->balance == 1 ) leftChild->balance = -1; else leftChild->balance = 0; t->balance = 0; }; /** * Handle the error of get element from an empty tree. */ template <typename Object, typename Key> void AVLTree<Object, Key>::handleUnderflow() { cerr << "The tree is empty!" << endl << endl; exit( 1 ); }
测试文件:
/***************************************************************************** * avltree_test.cpp * * Stack class testing. * * Zhang Ming, 2009-10 *****************************************************************************/ #include <iostream> #include <student.h> #include <avltree.h> using namespace std; using namespace itlab; int main() { int x[16] = { 3, 2, 1, 4, 5, 6, 7, 16, 15, 14, 13, 12, 11, 10, 8, 9 }; int y[16] = { 9, 4, 12, 6, 5, 2, 3, 15, 14, 7, 8, 1, 1, 3, 20, 12 }; int z[4] = { 10, 13, 5, 1 }; Student stu; AVLNode<Student, int> *pNode; AVLTree<Student, int> stuTree; for( int i=0; i<16; ++i ) { stu.key = x[i]; stuTree.insert( stu ); } cout << "Preorder Travesal: " << endl; stuTree.print( "preorder" ); cout << endl << endl; for( int i=0; i<16; ++i ) { if( stuTree.remove( y[i], stu ) ) { cout << "The removed item is: "<< stu; cout << "Preorder Travesal: " << endl; stuTree.print( "preorder" ); } else { cout << "No such item (key=" << y[i] << ") in the tree!"; } cout << endl << endl; } cout << endl; for( int i=0; i<4; ++i) { pNode = stuTree.search( z[i] ); if( pNode ) cout << "Have finding the element: " << pNode->data; else cout << "No such item (key=" << z[i] << ") in the tree!"; cout << endl; } cout << endl; stuTree.makeEmpty(); pNode = stuTree.search( 10 ); return 0; }