紅黑樹是知足下列性質的二叉樹:css
樹中只有紅色的節點和黑色的節點html
根節點是黑色的git
外部節點(NIL)都是黑色的
注意:這裏的外部節點指的是這樣的節點:
爲了節省空間可使他們指向同一個外部節點
對於C/C++語言來講能夠不設外部節點,若是一個節點沒有子節點,能夠將其節點的指針域置爲空,能夠視空節點
爲外部節點github
若是一個節點是紅色的,那麼它的左右孩子節點必須是黑色的web
對於每一個節點,從該節點到其全部後代外部節點的簡單路徑上,所通過黑色節點的個數相同,也稱爲"黑高"算法
根據上述性質,使用C++語言定義樹節點以下:json
enum RB_COLOR { RED, BLACK }; template<typename T> struct tagRBNode { struct tagRBNode<T> * m_pLeft; //指向左孩子 struct tagRBNode<T> * m_pRight; //指向右孩子 struct tagRBNode<T> * m_pParent;//指向父節點 RB_COLOR m_Color; //節點顏色 T m_TDataElemet; //數據域 tagRBNode(T & data, RB_COLOR bRed = RED) : m_pParent(nullptr), m_pLeft(nullptr), m_pRight(nullptr), m_TDataElemet(data), m_Color(bRed) { } }; /*定義模版節點類型別名*/ template<typename T> using RBNode = tagRBNode<T>; /*定義模版節點指針類型別名*/ template<typename T> using PRBNode = tagRBNode<T>*;
紅黑樹類模版定義以下:ruby
template<typename T> class CRBTree { PRBNode<T> m_Root; //指向根節點 int m_nNumOfNode; //記錄節點個數 public: CRBTree(); bool Insert(T && data); bool Insert(T & data); bool Delete(T && data); bool Delete(T & data); private: bool LRotate(PRBNode<T> ParentOfPair); bool RRotate(PRBNode<T> ParentOfPair); bool FixAfterInsert(PRBNode<T> pNewNode); PRBNode<T> FindNodeByData(T & data); bool ReplaceNode(PRBNode<T> pBeReplaced, PRBNode<T> pReplacer); bool FixAfterDelete(PRBNode<T> pAdjustNode, PRBNode<T> pParentOfAdjust); };
爲了讓代碼中的操做開起來更直觀可讀,定義了以下的宏:bash
#define IS_LEFT_CHID(parent,child) ((((parent)->m_pLeft) == (child)) ? true:false) #define IS_EMPTY(pointer) (((pointer) == nullptr)?true:false) #define SET_COLOR(pointer,color) \ do \ { \ if ((pointer) != nullptr) \ { \ (pointer)->m_Color = color; \ } \ } \ while(0) #define GET_COLOR(pointer)((pointer)->m_Color) #define SET_RED_COLOR(pointer) \ do \ { \ if((pointer) != nullptr) \ { \ (pointer)->m_Color = RED; \ } \ } while (0) #define SET_BLACK_COLOR(pointer) \ do \ { \ if((pointer) != nullptr) \ { \ (pointer)->m_Color = BLACK; \ } \ } while (0) #define IS_RED_COLOR(pointer) ((((pointer)->m_Color) == RED) ?true:false) #define IS_BLACK_COLOR(pointer) ((((pointer)->m_Color) == BLACK) ?true:false) #define SET_PARENT(parent, child) \ if(child != nullptr) \ { \ child->m_pParent = parent; \ } #define SET_LEFT_CHILD(parent,child) \ do \ { \ parent->m_pLeft = child; \ SET_PARENT(parent,child) \ } \ while(0) #define SET_RIGHT_CHILD(parent,child) \ do \ { \ parent->m_pRight = child; \ SET_PARENT(parent,child) \ } \ while(0) #define LINK_GRANDFATHER_GRANDSON(parent,grandson) \ do \ { \ if(parent->m_pParent == nullptr) \ { \ m_Root = grandson; \ }else if (parent->m_pParent->m_pLeft == parent) \ { \ parent->m_pParent->m_pLeft = grandson; \ } \ else \ { \ parent->m_pParent->m_pRight = grandson; \ } \ grandson->m_pParent = parent->m_pParent; \ }while(0)
S1,S2,S3指代整個子樹,X表示待旋轉節點的父節點markdown
左旋代碼實現:
/************************************************************************ // 函數名稱: CRBTree<T>::LRotate // 訪問權限: private // 函數功能: 對一對節點進行左旋 // 返回值: bool:成功返回true,失敗返回false // 參數: PRBNode<T> ParentOfPair:待左旋的父節點 // 注意: ParentOfPair必需要有右孩子 ************************************************************************/ template<typename T> bool CRBTree<T>::LRotate(PRBNode<T> ParentOfPair) { PRBNode<T> pRChildOfParent = ParentOfPair->m_pRight; if (ParentOfPair == nullptr || pRChildOfParent == nullptr) { return false; } LINK_GRANDFATHER_GRANDSON(ParentOfPair, pRChildOfParent); SET_RIGHT_CHILD(ParentOfPair, pRChildOfParent->m_pLeft); SET_PARENT(ParentOfPair, pRChildOfParent->m_pLeft); SET_LEFT_CHILD(pRChildOfParent, ParentOfPair); SET_PARENT(pRChildOfParent, ParentOfPair); return true; }
右旋代碼實現:
/************************************************************************ // 函數名稱: CRBTree<T>::RRotate // 訪問權限: private // 函數功能: 對一對節點進行右旋 // 返回值: bool:成功返回true,失敗返回false // 參數: PRBNode<T> ParentOfPair:待右旋的父節點 // 注意: ParentOfPair必需要有左孩子 ************************************************************************/ template<typename T> bool CRBTree<T>::RRotate(PRBNode<T> ParentOfPair) { PRBNode<T> pLChildOfParent = ParentOfPair->m_pLeft; if (ParentOfPair == nullptr || pLChildOfParent == nullptr) { return false; } LINK_GRANDFATHER_GRANDSON(ParentOfPair, pLChildOfParent); SET_LEFT_CHILD(ParentOfPair, pLChildOfParent->m_pRight); SET_PARENT(ParentOfPair, pLChildOfParent->m_pRight); SET_RIGHT_CHILD(pLChildOfParent, ParentOfPair); SET_PARENT(pLChildOfParent, ParentOfPair); return true; }
若是紅黑樹爲空則直接插入便可,若是紅黑樹不爲空,則須要使用相似"二分查找"的方式來找到合適的插入位置,
插入前節點須要着色,通常都是設置爲紅色,由於一個非空紅黑樹從根節點到任意葉節點的黑高是相同的,因此插入
一個紅色的節點不會影響所在路徑的黑高(性質5),可能會形成與其父節點都是紅色(性質4);可是若是講新節點着
黑色插入,那麼必定會影響所在路徑的黑高,則每次插入都必須作出調整
下面給出插入的實現代碼:
/************************************************************************ // 函數名稱: CRBTree<T>::Insert // 訪問權限: public // 函數功能: 插入一個值 // 返回值: bool:成功返回true,失敗返回false // 參數: T & data:要插入的值 // 注意: 1.傳入的參數data必須是一個左值 2.若是data已經存在則返回失敗 ************************************************************************/ template<typename T> bool CRBTree<T>::Insert(T & data) { /*先查找插入位置*/ PRBNode<T> pParentOfInsertLoc = m_Root; PRBNode<T> pSearchLoc = m_Root; while (pSearchLoc != nullptr) { pParentOfInsertLoc = pSearchLoc; if (pSearchLoc->m_TDataElemet < data) { pSearchLoc = pSearchLoc->m_pRight; } else if (pSearchLoc->m_TDataElemet > data) { pSearchLoc = pSearchLoc->m_pLeft; } else { /*帶插入的元素已經存在*/ return false; } } PRBNode<T> pNewNode = new RBNode<T>(data); if (pParentOfInsertLoc == nullptr) { /*樹爲空,則直接插入*/ m_Root = pNewNode; } else if(pParentOfInsertLoc->m_TDataElemet > data) { SET_LEFT_CHILD(pParentOfInsertLoc, pNewNode); SET_PARENT(pParentOfInsertLoc, pNewNode); } else { SET_RIGHT_CHILD(pParentOfInsertLoc, pNewNode); SET_PARENT(pParentOfInsertLoc, pNewNode); } m_nNumOfNode++; FixAfterInsert(pNewNode); return true; } /************************************************************************ // 函數名稱: CRBTree<T>::Insert // 訪問權限: public // 函數功能: 插入一個值 // 返回值: bool:成功返回true,失敗返回false // 參數: T & & data:節點值 // 注意: 1.傳入的參數data必須是一個右值 2.若是data已經存在則返回失敗 ************************************************************************/ template<typename T> bool CRBTree<T>::Insert(T && data) { return Insert(data); }
由於每次插入的新節點的顏色都是紅色,若是是一顆空樹插入根節點後,會破壞性質2;若是不是空樹,插入後可能破
壞性質4;也有可能不破壞性質4,若是插入後新節點的父節點爲黑色;因此插入新節點後要維持紅黑樹的性質,則從
維護這兩個性質開始:
根據上面的幾種情形得出下面是插入後維持紅黑樹性質的代碼:
/************************************************************************ // 函數名稱: CRBTree<T>::FixAfterInsert // 訪問權限: private // 函數功能: 插入新節點後調整以維護紅黑樹性質 // 返回值: bool // 參數: PRBNode<T> pNewNode:新插入的節點 // 注意: ************************************************************************/ template<typename T> bool CRBTree<T>::FixAfterInsert(PRBNode<T> pNewNode) { PRBNode<T> pParent = nullptr; PRBNode<T> pUncle = nullptr; PRBNode<T> pGrand = nullptr; PRBNode<T> pAdjust = pNewNode; while ((pParent = pAdjust->m_pParent) && IS_RED_COLOR(pParent)) { pGrand = pParent->m_pParent; if (IS_LEFT_CHID(pGrand, pParent)) { pUncle = pGrand->m_pRight; if (pUncle != nullptr && IS_RED_COLOR(pUncle)) { /*Case1:待調整節點的叔節點爲紅色,那麼祖父節點一定時黑色的,則將待調整節點父節點和叔節點置爲 置爲黑色,將祖父節點置爲紅色,並將待調整節點設置爲祖父節點 */ SET_BLACK_COLOR(pParent); SET_BLACK_COLOR(pUncle); SET_RED_COLOR(pGrand); pAdjust = pGrand; continue; } else { /*叔節點此時必定是黑色(不存在也視爲黑色)*/ if (!IS_LEFT_CHID(pParent, pAdjust)) { /*case2:待調整節點是其父節點的右孩子,則進行一次左旋,並重置待調整位置*/ pAdjust = pParent; LRotate(pParent); pParent = pAdjust->m_pParent; } /*Case3:此時待調整節點爲父節點的左孩子,將祖父節點置爲紅色,而後對祖父節點執行一次右旋, 調整就結束了*/ SET_BLACK_COLOR(pParent); SET_RED_COLOR(pGrand); RRotate(pGrand); } } else { pUncle = pGrand->m_pLeft; if (pUncle != nullptr && IS_RED_COLOR(pUncle)) { /*Case1:叔節點爲紅色*/ SET_BLACK_COLOR(pUncle); SET_BLACK_COLOR(pParent); SET_RED_COLOR(pGrand); pAdjust = pGrand; continue; } else { /*此時叔節點爲黑色(不存在也視爲黑色)*/ if (IS_LEFT_CHID(pParent, pAdjust)) { /*Case2:待調整節點是其父節點的左孩子,則對父節點進行右旋*/ pAdjust = pParent; RRotate(pParent); pParent = pAdjust->m_pParent; } /*Case3:此時待調整節點爲父節點的右孩子,將父節點置爲黑色,祖父節點置爲紅色, 在對祖父節點進行一次左旋便可結束調整*/ SET_BLACK_COLOR(pParent); SET_RED_COLOR(pGrand); LRotate(pGrand); } } } SET_BLACK_COLOR(m_Root); return true; }
插入前尋找插入位置的代碼複雜度與紅黑樹的高度有關,因此須要找出節點總個數n與樹高度h的關係;
設任意節點x的黑高爲hb(x)(不小於0),先證實任意節點x的至少含有2^hb(x)-1個內部節點:
當hb(x)=0時,節點x的是外部節點或者葉節點;x爲外部節點時,其內部節點的個數爲0,x爲葉節點時,x含有一個內
部節點就是它本身;則hb(x)=0時,至少含有2^hb(x)-1成立;
當節點x的hb(x)!=0時,也即hb(x)>0時,假設其左右孩子都存在,當孩子節點爲紅色時,孩子節點的黑高也爲hb(x);
當孩子節點爲黑色時,孩子節點的高度爲hb(x)-1;無論節點x的孩子節點是紅的仍是黑的,那麼孩子節點的黑高至少
是hb(x)-1,那麼節點x含有外部節點的個數至少爲(包括x本身):2^(hb(x)-1)-1+2^(hb(x)-1)-1+1,簡化後即
爲:2^hb(x)-1;這裏有子樹黑高hb(x)-1推出其父節點黑高爲hb(x)時至少含2^hb(x)-1內部節點,因此有數學
概括法能夠證實任意節點x的至少含有2^hb(x)-1個內部節點是正確的
假設紅黑樹的高度爲h節點總數爲n,由紅黑樹的性質4能夠推出從根節點到任意外部節點的簡單路徑上,黑節點的個
數至少爲h/2,則說明高度爲h的紅黑樹的黑高至少爲h/2,則說明根節點至少含有2^(h/2)-1個內部節點,能夠推出:
2^(h/2)-1<n,可推得2^(h/2)<n+1,不等式兩邊同時對2取對數後得:h/2<lg(n+1),最終能夠獲得高度h知足:
h<2lg(n+1),也就是說含n個節點的紅黑樹,高度至多爲2lg(n+1)
紅黑樹也是一種二叉樹,那麼其查找節點的時間複雜度T(n)=O(2lg(n+1))=O(lgn),因此紅黑樹中插入節點前查找
代碼時間複雜度爲O(n);插入後爲了維持紅黑樹的性質,須要沿着插入位置向根節點調整,若是違反了性質1,那麼
從新着色和調整位置向上移動兩層,因此循環最多執行lg(n+1)次;另外每次循環中旋轉的次數不會超過兩次,只要
進入了Case2和Case3執行兩次旋轉後,本次循環就結束了,因此維持插入後維持紅黑樹性質的代碼時間複雜度爲
O(lgn),因此插入總的時間複雜度爲O(lgn)
這裏爲了方便描述,稱待刪除節點爲D,其左孩子爲DL,右孩子爲DR,其父節點爲DP;用於替換待刪除節點的節點稱爲X,
它的左孩子稱爲XL,右孩子稱爲XR,其父節點稱爲XP,紅黑樹節點的刪除和二叉搜索樹刪除節點相似,分爲如下三種
狀況:
從上面三種狀況能夠看出節點的替換是一個經常使用操做,因此將此操做封裝爲一個成員函數:
/************************************************************************ // 函數名稱: CRBTree<T>::ReplaceNode // 訪問權限: private // 函數功能: 用pReplacer指向的節點替換pBeReplaced指向的節點 // 返回值: bool // 參數: PRBNode<T> pBeReplaced:待替換的節點 // 參數: PRBNode<T> pReplacer用於替換的節點 // 注意: pBeReplaced不能爲空 ************************************************************************/ template<typename T> bool CRBTree<T>::ReplaceNode(PRBNode<T> pBeReplaced, PRBNode<T> pReplacer) { if (pBeReplaced == nullptr) { return false; } if (pBeReplaced == m_Root) { /*根節點被替換*/ m_Root = pReplacer; SET_PARENT(nullptr, pReplacer); } else if (IS_LEFT_CHID(pBeReplaced->m_pParent, pBeReplaced)) { SET_LEFT_CHILD(pBeReplaced->m_pParent, pReplacer); } else { SET_RIGHT_CHILD(pBeReplaced->m_pParent, pReplacer); } return true; }
這個函數主要功能是創建DP(待刪除節點的父節點)與X(用於替換的節點)間的父子關係,可是沒有重置X與DL,DR
間的關係,若是要在這個函數中也完成X與DL,DR節點關係的創建,整個函數將會變得很複雜;
刪除一個節點前,必須如今紅黑樹中尋找這個待刪除節點,因此還須要實現一個查找的成員函數:
/************************************************************************ // 函數名稱: CRBTree<T>::FindNodeByData // 訪問權限: private // 函數功能: 查找樹中是否存在元素值爲data的節點 // 返回值: 返回指向該節點的指針,若是沒有該節點則返回空指針 // 參數: T & data:待查找的元素 // 注意: ************************************************************************/ template<typename T> PRBNode<T> CRBTree<T>::FindNodeByData(T & data) { PRBNode<T> pSearch = m_Root; while (pSearch != nullptr) { if (data > pSearch->m_TDataElemet) { pSearch = pSearch->m_pRight; } else if (data < pSearch->m_TDataElemet) { pSearch = pSearch->m_pLeft; } else { break; } } return pSearch; }
兩個輔助函數已經完成,下面則是刪除節點函數的實現:
/************************************************************************ // 函數名稱: CRBTree<T>::Delete // 訪問權限: public // 函數功能: 刪除一個節點元素爲data的節點 // 返回值: bool:成功返回true,失敗返回false // 參數: T & data:待查找的元素 // 注意: 1.data必須是一個左值,本函數用於支持左值做爲參數時調用 ************************************************************************/ template<typename T> bool CRBTree<T>::Delete(T & data) { PRBNode<T> pDelNode = FindNodeByData(data); PRBNode<T> pParentOfAdjust = nullptr; PRBNode<T> pAdjust = nullptr; if (pDelNode == nullptr) { return false; } RB_COLOR ColorRecorder = GET_COLOR(pDelNode); if (pDelNode->m_pLeft == nullptr) { /*左子樹爲空則直接使用右孩子來替換待刪除節點*/ pAdjust = pDelNode->m_pRight; pParentOfAdjust = pDelNode->m_pParent; ReplaceNode(pDelNode, pDelNode->m_pRight); } else if (pDelNode->m_pRight == nullptr) { /*右子樹爲空則使用待刪除節點左孩子來替換待刪除節點*/ pAdjust = pDelNode->m_pLeft; pParentOfAdjust = pDelNode->m_pParent; ReplaceNode(pDelNode, pDelNode->m_pLeft); } else { /*待刪除節點左右孩子都存在則從右子樹中選擇一個節點值最小的節點來替代待刪除節點*/ PRBNode<T> pMinNode = pDelNode->m_pRight; while (pMinNode->m_pLeft != nullptr) { pMinNode = pMinNode->m_pLeft; } ColorRecorder = GET_COLOR(pMinNode); pAdjust = pMinNode->m_pRight; pParentOfAdjust = pMinNode; if (pMinNode != pDelNode->m_pRight) { /*最小節點不是待刪除節點的右孩子,則先將最小節點從原來的位置上摘出來,最小值節點無左孩子,可能有右孩子, 將其右孩子和其父節點相互連接*/ ReplaceNode(pMinNode, pMinNode->m_pRight); pParentOfAdjust = pMinNode->m_pParent; /*將待刪除節點的右孩子置爲最小節點的右孩子*/ SET_RIGHT_CHILD(pMinNode, pDelNode->m_pRight); SET_PARENT(pMinNode, pMinNode->m_pRight); } /*用最小節點替換待刪除節點*/ ReplaceNode(pDelNode, pMinNode); SET_COLOR(pMinNode, GET_COLOR(pDelNode)); /*將待刪除節點的左孩子置爲最小節點的左孩子*/ SET_LEFT_CHILD(pMinNode, pDelNode->m_pLeft); SET_PARENT(pMinNode, pDelNode->m_pLeft); } if (ColorRecorder == BLACK) { /*被刪除的節點是黑色的或者替換節點爲黑色時,都會影響節點所在的簡單路徑上黑節點的個數,因此要調整*/ FixAfterDelete(pAdjust, pParentOfAdjust); } m_nNumOfNode--; delete pDelNode; return true; } /************************************************************************ // 函數名稱: CRBTree<T>::Delete // 訪問權限: public // 函數功能: 刪除一個節點元素爲data的節點 // 返回值: bool:成功返回true,失敗返回false // 參數: T & & data:待查找的元素 // 注意: 1.data必須是一個右值,本函數用於支持右值做爲參數時調用 ************************************************************************/ template<typename T> bool CRBTree<T>::Delete(T && data) { return Delete(data); }
D被刪除後,X坐在D原來的位置而且X的節點顏色被置爲D的顏色;那麼當X爲紅色時,用X取代D後不會影響X原來所在
簡單路徑上黑節點的個數,可是若是X爲黑色時,必定會影響X原來所在簡單路徑上黑節點的個數,這時須要從X移走
前的位置開始向上進行調整,以維持紅黑樹性質;
刪除節點後調整代碼的實現:
/************************************************************************ // 函數名稱: CRBTree<T>::FixAfterDelete // 訪問權限: private // 函數功能: 刪除節點後,從pAdjustNode指向的節點開始進行調整 // 返回值: bool // 參數: PRBNode<T> pAdjustNode:待調整節點位置 // 參數: PRBNode<T> pParentOfAdjust:待調整節點的父節點 // 注意: ************************************************************************/ template<typename T> bool CRBTree<T>::FixAfterDelete(PRBNode<T> pAdjustNode, PRBNode<T> pParentOfAdjust) { PRBNode<T> pBrother = nullptr; PRBNode<T> pAdjust = pAdjustNode; PRBNode<T> pParent = pParentOfAdjust; while ((pAdjust == nullptr || IS_BLACK_COLOR(pAdjust)) && pAdjust != m_Root) { if (IS_LEFT_CHID(pParent,pAdjust)) { pBrother = pParent->m_pRight; if(IS_RED_COLOR(pBrother)) { /*Case1:待調整節點的兄弟節點爲紅色,將兄弟節點置爲黑色,將父節點置爲紅色,並對父節點進行一次左旋*/ SET_BLACK_COLOR(pBrother); SET_RED_COLOR(pParent); LRotate(pParent); pBrother = pParent->m_pRight; } if ((pBrother->m_pLeft == nullptr || IS_BLACK_COLOR(pBrother->m_pLeft)) && (pBrother->m_pRight == nullptr || IS_BLACK_COLOR(pBrother->m_pRight))) { /*Case2:待調整節點的兄弟節點爲黑色,且兄弟節點的左右孩子都是黑色的(不存在也視爲黑色),則將兄弟節點 置爲紅色,並將其父節點置爲下一次的調整節點*/ SET_RED_COLOR(pBrother); pAdjust = pParent; pParent = pAdjust->m_pParent; } else { /*此時兄弟節點的左孩子一定存在而且是紅色的*/ if (pBrother->m_pRight == nullptr || IS_BLACK_COLOR(pBrother->m_pRight)) { /*Case3:兄弟節點是黑色的,兄弟節點的左孩子是紅色,兄弟節點的右孩子是黑色(不存在也視爲黑色), 將兄弟節點置爲紅色,兄弟節點的左孩子置爲黑色,並對兄弟節點進行一次右旋*/ SET_RED_COLOR(pBrother); SET_BLACK_COLOR(pBrother->m_pLeft); RRotate(pBrother); pBrother = pParent->m_pRight; } /*Case4:此時兄弟節點的右孩子一定是紅色的,左孩子無關緊要或者顏色任意,將父節點的顏色賦值給兄弟節點 並將父節點置爲黑色,在將兄弟節點的右孩子節點置爲黑色,而後對父節點進行一次左旋,並將待調整 節點置爲根節點,則調整結束*/ SET_COLOR(pBrother, GET_COLOR(pParent)); SET_BLACK_COLOR(pParent); SET_BLACK_COLOR(pBrother->m_pRight); LRotate(pParent); pAdjust = m_Root; } } else { pBrother = pParent->m_pLeft; if (IS_RED_COLOR(pBrother)) { /*Case1:待調整節點的兄弟節點爲紅色,將兄弟節點置爲黑色,將父節點置爲紅色,並對父節點進行一次左旋*/ SET_BLACK_COLOR(pBrother); SET_RED_COLOR(pParent); LRotate(pParent); pBrother = pParent->m_pRight; } if ((pBrother->m_pLeft == nullptr || IS_BLACK_COLOR(pBrother->m_pLeft)) && (pBrother->m_pRight == nullptr || IS_BLACK_COLOR(pBrother->m_pRight))) { /*Case2:待調整節點的兄弟節點爲黑色,兄弟節點的兩個子節點也是黑色的,則將兄弟節點置爲紅色, 並將父節點置爲下一次的調整節點*/ SET_RED_COLOR(pBrother); pAdjust = pParent; pParent = pAdjust->m_pParent; } else { if (pBrother->m_pLeft == nullptr || IS_BLACK_COLOR(pBrother->m_pLeft)) { /*Case3:待調整節點的兄弟節點爲黑色,兄弟的左孩子節點爲黑色,右孩子節點爲紅色,則將兄弟節點置爲紅色, 將兄弟節點的右孩子置爲黑色,並對兄弟進行左旋*/ SET_RED_COLOR(pBrother); SET_BLACK_COLOR(pBrother->m_pRight); LRotate(pBrother); pBrother = pParent->m_pLeft; } /*Case3:此時待調整節點的兄弟節點是黑色的,兄弟節點的左孩子是紅色的,將父節點的顏色賦值給兄弟節點, 並將父節點置爲黑色,將兄弟節點的左孩子置爲黑色,並對父節點進行一次右旋,並將下次調整節點置 爲根節點,則調整結束*/ SET_COLOR(pBrother, GET_COLOR(pParent)); SET_BLACK_COLOR(pBrother->m_pLeft); SET_BLACK_COLOR(pParent); RRotate(pParent); pAdjust = m_Root; } } } SET_BLACK_COLOR(pAdjust); return true; }
n個節點的紅黑樹的高度爲lg(n),刪除節點前查找節點的時間複雜度爲O(lgn),在查找待刪除節點右子樹中最小
節點值的操做時間複雜度不超過O(lgn),在刪除節點後修復過程當中,對於Case1,3,4至多旋轉3次就結束調整了,
因此時間複雜度爲O(1),Case2情形下是循環能夠重複執行的惟一狀況,從葉節點調整到根節點最多耗時O(lgn),
因此整個刪除操做時間複雜度爲lgn