前言:html
節主要是給出BST,AVL和紅黑樹的C++代碼,方便本身之後的查閱,其代碼依舊是data structures and algorithm analysis in c++ (second edition)一書的做者所給,關於這3中二叉樹在前面的博文算法設計和數據結構學習_4(《數據結構和問題求解》part4筆記)中已經有所介紹。這裏不會去詳細介紹它們的實現和規則,一是由於這方面的介紹性資料超很是多,另外這3種樹的難點都在插入和刪除部分,其規則自己並很少,可是要用文字和圖形解釋其實還蠻耗時的。因此,咱們在看教程時,主要是要抓住這幾種樹的思想,而後對照對應的代碼來看就ok了,能把代碼看懂基本也就理解這些樹的本質了。node
BST& AVL樹:c++
BST即二叉搜索樹,它只需知足A節點左子樹的值都小於A的值,右子樹的值都大於A節點的值。其插入過程是依照它的屬性值依次插入,刪除過程分2種狀況,若是是葉子節點,直接刪除,若是是非葉子節點,則刪除後將它的左子樹中的最大節點填補,若是左子樹爲空,則用右子樹中的最小節點填補。算法
AVL樹的構造過程當中有下面四種狀況須要調整,有可能只需旋轉一次,有可能須要旋轉2次。數組
1. 單向右旋轉(不平衡節點)平衡處理:數據結構
當在左子樹上插入左節點,使平衡因子由1增長至2時。app
2. 單向左旋轉(不平衡節點)平衡處理:less
當在右子樹上插入右節點,使平衡因子由-1增長至-2時。dom
3. 雙向旋轉(先左旋轉不平衡節點左孩子,而後右旋轉不平衡節點)平衡處理:ide
當在左子樹上插入右節點,使平衡因子有1增長到2時。
4. 雙向旋轉(先右旋轉不平衡節點右孩子,而後左旋轉不平衡節點)平衡處理:
當在右子樹上插入左節點,使平衡因子由-1增長至-2時。
BST類實現的code以下(AVL相似):
BinarySearchTree.h:
#ifndef BINARY_SEARCH_TREE_H_ #define BINARY_SEARCH_TREE_H_ #include "Wrapper.h" template <class Comparable> class BinarySearchTree; template <class Comparable> class BinarySearchTreeWithRank; template <class Comparable> class BinaryNode { Comparable element; BinaryNode *left; BinaryNode *right; int size; BinaryNode( const Comparable & theElement, BinaryNode *lt, BinaryNode *rt, int sz = 1 ) : element( theElement ), left( lt ), right( rt ), size( sz ) { } friend class BinarySearchTree<Comparable>; friend class BinarySearchTreeWithRank<Comparable>; }; // BinarySearchTree class // // CONSTRUCTION: with no parameters or another BinarySearchTree. // // ******************PUBLIC OPERATIONS********************* // void insert( x ) --> Insert x // void remove( x ) --> Remove x // void removeMin( ) --> Remove smallest item // Comparable find( x ) --> Return item that matches x // Comparable findMin( ) --> Return smallest item // Comparable findMax( ) --> Return largest item // bool isEmpty( ) --> Return true if empty; else false // void makeEmpty( ) --> Remove all items // ******************ERRORS******************************** // Exceptions are thrown by insert, remove, and removeMin if warranted template <class Comparable> class BinarySearchTree { public: BinarySearchTree( ); BinarySearchTree( const BinarySearchTree & rhs ); virtual ~BinarySearchTree( ); Cref<Comparable> findMin( ) const; Cref<Comparable> findMax( ) const; Cref<Comparable> find( const Comparable & x ) const; bool isEmpty( ) const; void makeEmpty( ); void insert( const Comparable & x ); void remove( const Comparable & x ); void removeMin( ); const BinarySearchTree & operator=( const BinarySearchTree & rhs ); typedef BinaryNode<Comparable> Node; protected: Node *root; Cref<Comparable> elementAt( Node *t ) const; virtual void insert( const Comparable & x, Node * & t ) const; virtual void remove( const Comparable & x, Node * & t ) const; virtual void removeMin( Node * & t ) const; Node * findMin( Node *t ) const; Node * findMax( Node *t ) const; Node * find( const Comparable & x, Node *t ) const; void makeEmpty( Node * & t ) const; Node * clone( Node *t ) const; }; // BinarySearchTreeWithRank class. // // CONSTRUCTION: with no parameters or // another BinarySearchTreeWithRank. // // ******************PUBLIC OPERATIONS********************* // Comparable findKth( k )--> Return kth smallest item // All other operations are inherited (but C++ requires // some extra stuff). template <class Comparable> class BinarySearchTreeWithRank : public BinarySearchTree<Comparable> { public: Cref<Comparable> findKth( int k ) const; void insert( const Comparable & x ) { BinarySearchTree<Comparable>::insert( x ); } void remove( const Comparable & x ) { BinarySearchTree<Comparable>::remove( x ); } void removeMin( ) { BinarySearchTree<Comparable>::removeMin( ); } typedef BinaryNode<Comparable> Node; private: void insert( const Comparable & x, Node * & t ) const; void remove( const Comparable & x, Node * & t ) const; void removeMin( Node * & t ) const; Node *findKth( int k, Node *t ) const; int treeSize( Node *t ) const { return t == NULL ? 0 : t->size; } }; #include "BinarySearchTree.cpp" #endif
BinarySearchTree.cpp:
#include "BinarySearchTree.h" #include "Except.h" // Construct the tree. template <class Comparable> BinarySearchTree<Comparable>::BinarySearchTree( ) : root( NULL ) { } // Copy constructor. template <class Comparable> BinarySearchTree<Comparable>:: BinarySearchTree( const BinarySearchTree<Comparable> & rhs ) : root( NULL ) { *this = rhs; } // Destructor for the tree. template <class Comparable> BinarySearchTree<Comparable>::~BinarySearchTree( ) { makeEmpty( ); } // Insert x into the tree; // Throws DuplicateItemException if x is already there. template <class Comparable> void BinarySearchTree<Comparable>::insert( const Comparable & x ) { insert( x, root ); } // Remove x from the tree. // Throws ItemNotFoundException if x is not in the tree. template <class Comparable> void BinarySearchTree<Comparable>::remove( const Comparable & x ) { remove( x, root ); } // Remove minimum item from the tree. // Throws UnderflowException if tree is empty. template <class Comparable> void BinarySearchTree<Comparable>::removeMin( ) { removeMin( root ); } // Return the smallest item in the tree wrapped in a Cref object. template <class Comparable> Cref<Comparable> BinarySearchTree<Comparable>::findMin( ) const { return elementAt( findMin( root ) ); } // Return the largest item in the tree wrapped in a Cref object. template <class Comparable> Cref<Comparable> BinarySearchTree<Comparable>::findMax( ) const { return elementAt( findMax( root ) ); } // Find item x in the tree. // Return the matching item wrapped in a Cref object. template <class Comparable> Cref<Comparable> BinarySearchTree<Comparable>::find( const Comparable & x ) const { return elementAt( find( x, root ) ); } // Make the tree logically empty. template <class Comparable> void BinarySearchTree<Comparable>::makeEmpty( ) { makeEmpty( root ); } // Test if the tree is logically empty. // Return true if empty, false otherwise. template <class Comparable> bool BinarySearchTree<Comparable>::isEmpty( ) const { return root == NULL; } // Deep copy. template <class Comparable> const BinarySearchTree<Comparable> & BinarySearchTree<Comparable>:: operator=( const BinarySearchTree<Comparable> & rhs ) { if( this != &rhs ) { makeEmpty( ); root = clone( rhs.root ); } return *this; } // Internal method to wrap the element field in node t inside a Cref object. template <class Comparable> Cref<Comparable> BinarySearchTree<Comparable>::elementAt( Node *t ) const { if( t == NULL ) return Cref<Comparable>( ); else return Cref<Comparable>( t->element ); } // Internal method to insert into a subtree. // x is the item to insert. // t is the node that roots the tree. // Set the new root. // Throw DuplicateItemException if x is already in t. template <class Comparable> void BinarySearchTree<Comparable>:: insert( const Comparable & x, Node * & t ) const { if( t == NULL ) t = new Node( x, NULL, NULL ); else if( x < t->element ) insert( x, t->left ); else if( t->element < x ) insert( x, t->right ); else throw DuplicateItemException( ); } // Internal method to remove from a subtree. // x is the item to remove. // t is the node that roots the tree. // Set the new root. // Throw ItemNotFoundException is x is not in t. template <class Comparable> void BinarySearchTree<Comparable>:: remove( const Comparable & x, Node * & t ) const { if( t == NULL ) throw ItemNotFoundException( ); if( x < t->element ) remove( x, t->left ); else if( t->element < x ) remove( x, t->right ); else if( t->left != NULL && t->right != NULL ) // Two children { t->element = findMin( t->right )->element; removeMin( t->right ); // Remove minimum } else { BinaryNode<Comparable> *oldNode = t; t = ( t->left != NULL ) ? t->left : t->right; // Reroot t delete oldNode; // delete old root } } // Internal method to remove minimum item from a subtree. // t is the node that roots the tree. // Set the new root. // Throw UnderflowException if t is empty. template <class Comparable> void BinarySearchTree<Comparable>::removeMin( Node * & t ) const { if( t == NULL ) throw UnderflowException( ); else if( t->left != NULL ) removeMin( t->left ); else { Node *tmp = t; t = t->right; delete tmp; } } // Internal method to find the smallest item in a subtree t. // Return node containing the smallest item. template <class Comparable> BinaryNode<Comparable> * BinarySearchTree<Comparable>::findMin( Node *t ) const { if( t != NULL ) while( t->left != NULL ) t = t->left; return t; } // Internal method to find the largest item in a subtree t. // Return node containing the largest item. template <class Comparable> BinaryNode<Comparable> * BinarySearchTree<Comparable>::findMax( Node *t ) const { if( t != NULL ) while( t->right != NULL ) t = t->right; return t; } // Internal method to find an item in a subtree. // x is item to search for. // t is the node that roots the tree. // Return node containing the matched item. template <class Comparable> BinaryNode<Comparable> * BinarySearchTree<Comparable>:: find( const Comparable & x, Node *t ) const { while( t != NULL ) if( x < t->element ) t = t->left; else if( t->element < x ) t = t->right; else return t; // Match return NULL; // Not found } // Internal method to make subtree empty. template <class Comparable> void BinarySearchTree<Comparable>::makeEmpty( Node * & t ) const { if( t != NULL ) { makeEmpty( t->left ); makeEmpty( t->right ); delete t; } t = NULL; } // Internal method to clone subtree. template <class Comparable> BinaryNode<Comparable> * BinarySearchTree<Comparable>::clone( Node * t ) const { if( t == NULL ) return NULL; else return new Node( t->element, clone( t->left ), clone( t->right ), t->size ); } // Returns the kth smallest item in the tree. // Throws ItemNotFoundException if k is out of range. template <class Comparable> Cref<Comparable> BinarySearchTreeWithRank<Comparable>::findKth( int k ) const { return elementAt( findKth( k, root ) ); } // Internal method to insert into a subtree. // x is the item to insert. // t is the node that roots the tree. // Set the new root. // Throw DuplicateItemException if x is already in t. template <class Comparable> void BinarySearchTreeWithRank<Comparable>:: insert( const Comparable & x, Node * & t ) const { if( t == NULL ) t = new Node( x, NULL, NULL, 0 ); else if( x < t->element ) insert( x, t->left ); else if( t->element < x ) insert( x, t->right ); else throw DuplicateItemException( ); t->size++; } // Internal method to remove from a subtree. // x is the item to remove. // t is the node that roots the tree. // Set the new root. // Throw ItemNotFoundException is x is not in t. template <class Comparable> void BinarySearchTreeWithRank<Comparable>:: remove( const Comparable & x, Node * & t ) const { if( t == NULL ) throw ItemNotFoundException( ); if( x < t->element ) remove( x, t->left ); else if( t->element < x ) remove( x, t->right ); else if( t->left != NULL && t->right != NULL ) // Two children { t->element = findMin( t->right )->element; removeMin( t->right ); // Remove minimum } else { BinaryNode<Comparable> *oldNode = t; t = ( t->left != NULL ) ? t->left : t->right; // Reroot t delete oldNode; // delete old root return; } t->size--; } // Internal method to remove minimum item from a subtree. // t is the node that roots the tree. // Set the new root. // Throw UnderflowException if t is empty. template <class Comparable> void BinarySearchTreeWithRank<Comparable>::removeMin( Node * & t ) const { if( t == NULL ) throw UnderflowException( ); else if( t->left != NULL ) removeMin( t->left ); else { Node *tmp = t; t = t->right; delete tmp; return; } t->size--; } // Internal method to find kth item in a subtree. // k is the desired rank. // t is the node that roots the tree. template <class Comparable> BinaryNode<Comparable> * BinarySearchTreeWithRank<Comparable>::findKth( int k, Node * t ) const { if( t == NULL ) return NULL; int leftSize = treeSize( t->left ); if( k <= leftSize ) return findKth( k, t->left ); else if( k == leftSize + 1 ) return t; else return findKth( k - leftSize - 1, t->right ); }
紅黑樹:
3個連續的節點構成的樹不多是Red-Black樹。
Log(n)基本上接近常量,好比說宇宙中原子的個數爲10^69,取log後(10爲底的狀況)也只有69了,因此若是某個算法是log(n)的複雜度,那麼這個算法是至關好的了。
靜態查找表通常用數組實現,而動態查找表通常用樹實現。查找表的實現還有鍵樹,trie樹,hash表等。
BST查找必定要從根節點開始,且BST的插入,查找算法通常都要用遞歸算法實現。能夠從2-3樹過渡到紅黑樹(紅黑樹的本質就是2-3-4樹,比2-3樹稍微複雜一點),2-3樹是指每一個節點的分支能夠有2個或者3個。
紅黑樹中的紅節點都對應於2-3-4樹中大節點(指該節點內可能有2個或者3個數據)中的內部節點。
紅黑樹的查找性能和AVL相對,稍弱一點,可是實踐代表,紅黑樹的插入過程當中所須要進行的節點旋轉次數比AVL樹的要小。
2-3-4樹是一顆B樹,屬於外部查找樹。
紅黑樹的插入:
按照插入節點的值從紅黑樹的根節點依次往下插入。若是碰到其path上的節點左右節點都是紅色的,則須要進行節點的顏色變換,顏色變換後若是出現了2個連續的紅色節點,則須要進行旋轉,旋轉過程當中固然也會有顏色變換。 直到找到須要插入的位置將其插入,由於插入的節點只能是紅色的,因此又可能引發2個連續的紅色節點,這時候仍然須要使用上面的規則進行調整。
紅黑樹的類實現code以下:
RedBlackTree.h:
#ifndef RED_BLACK_TREE_H_ #define RED_BLACK_TREE_H_ #include "Wrapper.h" // Red-black tree class. // // CONSTRUCTION: with negative infinity object // // ******************PUBLIC OPERATIONS********************* // void insert( x ) --> Insert x // void remove( x ) --> Remove x (unimplemented) // Comparable find( x ) --> Return item that matches x // Comparable findMin( ) --> Return smallest item // Comparable findMax( ) --> Return largest item // bool isEmpty( ) --> Return true if empty; else false // void makeEmpty( ) --> Remove all items // ******************ERRORS******************************** // Throws exceptions as warranted. template <class Comparable> class RedBlackTree; template <class Comparable> class RedBlackNode; template <class Comparable> class RedBlackTree { public: RedBlackTree( const Comparable & negInf ); RedBlackTree( const RedBlackTree & rhs ); ~RedBlackTree( ); Cref<Comparable> findMin( ) const; Cref<Comparable> findMax( ) const; Cref<Comparable> find( const Comparable & x ) const; bool isEmpty( ) const; void makeEmpty( ); void insert( const Comparable & x ); void remove( const Comparable & x ); enum { RED, BLACK }; const RedBlackTree & operator=( const RedBlackTree & rhs ); typedef RedBlackNode<Comparable> Node; private: Node *header; // The tree header (contains negInf) Node *nullNode; // Used in insert routine and its helpers (logically static) Node *current; Node *parent; Node *grand; Node *great; // Usual recursive stuff void reclaimMemory( Node *t ) const; RedBlackNode<Comparable> * clone( Node * t ) const; // Red-black tree manipulations void handleReorient( const Comparable & item ); RedBlackNode<Comparable> * rotate( const Comparable & item, Node *parent ) const; void rotateWithLeftChild( Node * & k2 ) const; void rotateWithRightChild( Node * & k1 ) const; }; template <class Comparable> class RedBlackNode { Comparable element; RedBlackNode *left; RedBlackNode *right; int color; RedBlackNode( const Comparable & theElement = Comparable( ), RedBlackNode *lt = NULL, RedBlackNode *rt = NULL, int c = RedBlackTree<Comparable>::BLACK ) : element( theElement ), left( lt ), right( rt ), color( c ) { } friend class RedBlackTree<Comparable>; }; #include "RedBlackTree.cpp" #endif
RedBlackTree.cpp:
#include "RedBlackTree.h" #include "Except.h" // Construct the tree. // negInf is a value less than or equal to all others. template <class Comparable> RedBlackTree<Comparable>::RedBlackTree( const Comparable & negInf ) { nullNode = new Node;//空節點 nullNode->left = nullNode->right = nullNode; header = new Node( negInf );//頭節點,指向本身 header->left = header->right = nullNode; } // Copy constructor. template <class Comparable> RedBlackTree<Comparable>::RedBlackTree( const RedBlackTree<Comparable> & rhs ) { nullNode = new Node; nullNode->left = nullNode->right = nullNode; header = new Node( rhs.header->element );//只用rhs樹中的頭節點內容構造本身的頭節點 header->left = header->right = nullNode; *this = rhs; } // Destroy the tree. template <class Comparable> RedBlackTree<Comparable>::~RedBlackTree( ) { makeEmpty( ); delete nullNode; delete header; } // Insert item x into the tree. // Throws DuplicateItemException if x is already present. template <class Comparable> void RedBlackTree<Comparable>::insert( const Comparable & x ) { current = parent = grand = header;//一開始都定義爲頭節點 nullNode->element = x; while( current->element != x )//通常狀況下剛調用該函數時這個whlie條件是知足的,由於此時的current->element爲無窮小 { great = grand; grand = parent; parent = current;//所有更新 current = x < current->element ? current->left : current->right; // Check if two red children; fix if so if( current->left->color == RED && current->right->color == RED )//此時等價於2-3-4樹中的4節點,所以須要將中間的節點往父節點方向上長 handleReorient( x );//往上生長節點,包括旋轉和顏色變換 } // Insertion fails if already present if( current != nullNode ) throw DuplicateItemException( ); current = new Node( x, nullNode, nullNode );//其實current永遠是須要查找的下一個,有點先行的味道 // Attach to parent if( x < parent->element ) parent->left = current; else parent->right = current; handleReorient( x ); } // Remove item x from the tree. // Not implemented in this version. template <class Comparable> void RedBlackTree<Comparable>::remove( const Comparable & x ) { cout << "Sorry, remove unimplemented; " << x << " still present" << endl; } // Find the smallest item the tree. // Return the smallest item wrapped in a Cref object. template <class Comparable> Cref<Comparable> RedBlackTree<Comparable>::findMin( ) const { if( isEmpty( ) ) return Cref<Comparable>( ); Node *itr = header->right; while( itr->left != nullNode ) itr = itr->left; return Cref<Comparable>( itr->element ); } // Find the largest item in the tree. // Return the largest item wrapped in a Cref object. template <class Comparable> Cref<Comparable> RedBlackTree<Comparable>::findMax( ) const { if( isEmpty( ) ) return Cref<Comparable>( ); Node *itr = header->right; while( itr->right != nullNode ) itr = itr->right; return Cref<Comparable>( itr->element ); } // Find item x in the tree. // Return the matching item wrapped in a Cref object. template <class Comparable> Cref<Comparable> RedBlackTree<Comparable>::find( const Comparable & x ) const { nullNode->element = x; Node *curr = header->right; for( ; ; ) { if( x < curr->element ) curr = curr->left; else if( curr->element < x ) curr = curr->right; else if( curr != nullNode ) return Cref<Comparable>( curr->element ); else return Cref<Comparable>( ); } } // Make the tree logically empty. template <class Comparable> void RedBlackTree<Comparable>::makeEmpty( ) { reclaimMemory( header->right ); header->right = nullNode; } // Test if the tree is logically empty. // Return true if empty, false otherwise. template <class Comparable> bool RedBlackTree<Comparable>::isEmpty( ) const { return header->right == nullNode; } // Deep copy. template <class Comparable> const RedBlackTree<Comparable> & RedBlackTree<Comparable>::operator=( const RedBlackTree<Comparable> & rhs ) { if( this != &rhs ) { makeEmpty( ); header->right = clone( rhs.header->right ); } return *this; } // Internal method to clone subtree. template <class Comparable> RedBlackNode<Comparable> * RedBlackTree<Comparable>::clone( Node * t ) const { if( t == t->left ) // Cannot test against nullNode!!! return nullNode; else return new RedBlackNode<Comparable>( t->element, clone( t->left ), clone( t->right ), t->color ); } // Internal routine that is called during an insertion // if a node has two red children. Performs flip and rotations. // item is the item being inserted. template <class Comparable> void RedBlackTree<Comparable>::handleReorient( const Comparable & item ) { // Do the color flip current->color = RED; current->left->color = BLACK;//空節點也被認爲是黑色的 current->right->color = BLACK; if( parent->color == RED ) // Have to rotate { grand->color = RED; if( item < grand->element != item < parent->element )//這個條件表示item是grand的內子孫,所以須要2次調整 parent = rotate( item, grand ); // Start dbl rotate current = rotate( item, great ); current->color = BLACK; } header->right->color = BLACK; // Make root black,head實際上是根節點 } // Internal routine that performs a single or double rotation. // Because the result is attached to the parent, there are four cases. // Called by handleReorient. // item is the item in handleReorient. // parent is the parent of the root of the rotated subtree. // Return the root of the rotated subtree. template <class Comparable> RedBlackNode<Comparable> * RedBlackTree<Comparable>::rotate( const Comparable & item, Node *theParent ) const { if( item < theParent->element ) { item < theParent->left->element ? rotateWithLeftChild( theParent->left ) : // LL rotateWithRightChild( theParent->left ) ; // LR return theParent->left; } else { item < theParent->right->element ? rotateWithLeftChild( theParent->right ) : // RL rotateWithRightChild( theParent->right ); // RR return theParent->right; } } // Rotate binary tree node with left child. template <class Comparable> void RedBlackTree<Comparable>:: rotateWithLeftChild( Node * & k2 ) const { Node *k1 = k2->left; k2->left = k1->right; k1->right = k2; k2 = k1; } // Rotate binary tree node with right child. template <class Comparable> void RedBlackTree<Comparable>:: rotateWithRightChild( Node * & k1 ) const { Node *k2 = k1->right; k1->right = k2->left; k2->left = k1; k1 = k2; } // Internal method to reclaim internal nodes in subtree t. template <class Comparable> void RedBlackTree<Comparable>::reclaimMemory( Node *t ) const { if( t != t->left ) { reclaimMemory( t->left ); reclaimMemory( t->right ); delete t; } }
參考資料:
data structures and algorithm analysis in c++ (second edition),mark allen Weiss.