日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > c/c++ >内容正文

c/c++

真c++ 从二叉树到红黑树(4)之二叉平衡搜索树AVL

發布時間:2023/12/8 c/c++ 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 真c++ 从二叉树到红黑树(4)之二叉平衡搜索树AVL 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

??此文章為從二叉樹到紅黑樹系列文章的第四節,主要介紹介紹二叉平衡搜索樹AVL,當你理解了AVL,紅黑樹你就理解了一半了!


文章目錄

  • 一、前面文章鏈接~(點擊右邊波浪線可以返回目錄)
  • 二、由BST引入BBST~
    • 1.理想平衡~
    • 2.適度平衡~
    • 3.等價變換~
  • 三、AVL樹的定義~
    • 1.AVL樹的適度平衡~
    • 2.AVL樹的平衡因子~
  • 四、AVL類~
    • (一)定義變量和接口~
      • 1.利用已有的成員變量~
      • 2.需要的接口~
      • 3.重要輔助函數~
      • 4.AVL.h~
    • (二)判斷是否失衡~
    • (三)AVL的失衡與重平衡~
      • 1.因插入引起的失衡~
        • (1)LL型失衡~
        • (2)RR型失衡~
        • (3)LR型失衡~
        • (4)RL型失衡~
      • 2.因刪除引起的失衡~
        • (1)LL型失衡~
        • (2)RR型失衡~
        • (3)LR型失衡~
        • (4)RL型失衡~
      • 3.失衡情況總結~
      • 4.統一重平衡算法~
        • (1)萬能的connect 3+4算法~
          • connece34代碼~
        • (2)萬能的rotateAt算法~
          • rotateAt代碼~
    • (四)AVL的插入~
      • 插入代碼~
      • tallerChild函數~
      • 效率分析~
    • (五)AVL的刪除~
      • 刪除代碼~
      • 效率分析~
  • 五、完整AVL.h~
  • 六、測試代碼~
    • 1.插入測試代碼~
    • 2.插入測試圖示~
    • 3.刪除測試代碼~
    • 4.刪除測試圖示~
  • 七、后序文章鏈接~

一、前面文章鏈接~(點擊右邊波浪線可以返回目錄)

??在閱讀本文前,強烈建議你看下前面的文章的目錄、前言以及基本介紹,否則你無法理解后面的內容。鏈接如下:

  • 基本二叉樹節點,通用函數 二叉樹節點
  • 基本二叉樹類的定義和實現 二叉樹基類
  • BST(二叉搜索樹的實現) BST
  • 二、由BST引入BBST~

    ??在介紹AVL之前,我們先來了解下什么叫二叉平衡搜索樹(BBST)以及為什么要引入BBST。

    1.理想平衡~

    ??既然二叉搜索樹的性能主要取決于高度,故在節點數目固定的前提下,應盡可能地降低高度

    ??若樹高恰好為?log2n?(二叉樹的最低高度),則稱作理想平衡樹。如滿二叉樹和完全二叉樹。

    ??遺憾的是,完全二叉樹 “葉節點只能出現于最底部兩層” 的限制過于苛刻。所以要制定某種寬松的標準來實現適度平衡。

    2.適度平衡~

    ??將樹高限制為“漸進地不超過log2n”。如AVL,RedBlack等。

    3.等價變換~

    ??若兩棵樹的中序遍歷序列相同,則彼此等價。

    三、AVL樹的定義~

    1.AVL樹的適度平衡~

    左右兄弟節點的高度相差不過1。

    2.AVL樹的平衡因子~

    ??由適度平衡的定義不難得知,要保持一顆AVL樹的平衡,必須使其左右子樹的高度相差不超過1.故用數學的方式可以理解為:

    平衡因子(BalanceFactor)=左子樹高度-右子樹高度 平衡因子的絕對值不超過1。

    四、AVL類~

    (一)定義變量和接口~

    1.利用已有的成員變量~

    ??由于AVL樹屬于BST的一種,因此AVL樹可以繼承自BST,而BST又繼承自BinTree(二叉樹),而在此前(本系列文章第2節,第3節中),我們已經擁有了以下成員變量,因此不需要額外給AVL定義變量。

    BinNodePtr _hot;//"命中節點"的"父親"int _size;//二叉樹的規模 BinNodePtr _root;//二叉樹的樹根

    2.需要的接口~

    ??由于在BST中,我們已經定義了查找search算法,因此,不需要給AVL重新寫查找算法,只需要對插入和刪除算法進行重寫既可,AVL和BST的插入和刪除算法,本質上沒有區別,有區別的僅僅是插入和刪除之后的調整,而這種調整正是AVL與BST的最大差別所在。

    在樹中插入一個節點insert 在樹中刪除一個節點remove

    3.重要輔助函數~

    ??在AVL中,引入了一個平衡因子的概念,所以需要一個函數,來判斷此時的AVL樹是否平衡。

    判斷是否平衡的函數IsAvlBalanced

    ??并且還需要一個重要的輔助函數來得到當前節點的最高的那個孩子節點(這個函數在描述AVL的插入刪除算法時就會發揮作用)

    得到該節點更高的孩子tallerChild

    ??此外,不要忘了在BST中遺留的兩個函數,在介紹重平衡時,也會描述這兩個算法的作用

    3+4重構 connect34 對該節點及其父親、祖父做統一旋轉調整rotateAt

    4.AVL.h~

    template<typename T = int> class AVL :public BST<T> {protected:using BinNodePtr = BinNode<T>*;public:BinNodePtr insert(const T& data)override;//插入(重寫)bool remove(const T& data)override;//刪除(重寫)protected:static constexpr bool IsAvlBalanced(const BinNodePtr& x) {//判斷是否平衡int BalanceFactor = stature(x->_lchild) - stature(x->_rchild);return (-2 < BalanceFactor && BalanceFactor < 2);}static BinNodePtr& tallerChild(BinNode<T>*& x);//更高的孩子 };//class AVL

    (二)判斷是否失衡~

    ??借助AVL樹的平衡因子的概念,不難寫出判斷是否平衡的代碼。其中stature是在本系列文章第一部分定義的得出當前節點高度的全局靜態函數。

    static constexpr bool IsAvlBalanced(const BinNodePtr& x) {//判斷是否平衡int BalanceFactor = stature(x->_lchild) - stature(x->_rchild);return (-2 < BalanceFactor && BalanceFactor < 2); }

    ??AVL樹失衡時,當且僅當IsAvlBalanced函數的返回值為false。

    (三)AVL的失衡與重平衡~

    ??當AVL的平衡因子不再滿足平衡條件時,AVL就會發生失衡,而失衡無外乎就四種失衡情況,接下來,我們通過具體的例子來看看因為插入和刪除引起的AVL的失衡。

    1.因插入引起的失衡~

    (1)LL型失衡~

    ??下圖5 3由于2的插入,導致5的失衡,所以進行重平衡,即將3提升為根節點,5作為3的右孩子。

    (2)RR型失衡~

    ??下圖2 3由于4的插入,導致2的失衡,所以進行重平衡,即將3提升為根節點,2作為3的左孩子。

    (3)LR型失衡~

    ??下圖3 1由于2的插入,導致3的失衡,所以進行重平衡,即將2提升為根節點,1作為2的左孩子,3作為2的右孩子。

    (4)RL型失衡~

    ??下圖3 5由于4的插入,導致3的失衡,所以進行重平衡,即將4提升為根節點,3作為4的左孩子,5作為4的右孩子。

    2.因刪除引起的失衡~

    (1)LL型失衡~

    ??下圖3 2 5 1由于5的插入,導致3的失衡,所以進行重平衡,即將2提升為根節點,3作為2的右孩子。

    (2)RR型失衡~

    ??下圖3 2 4 5由于2的刪除,導致3的失衡,所以進行重平衡,即將4提升為根節點,3作為4的左孩子。

    (3)LR型失衡~

    ??下圖4 2 5 3由于5的刪除,導致4的失衡,所以進行重平衡,即將3提升為根節點,2作為3的左孩子,4作為3的右孩子。

    (4)RL型失衡~

    ??下圖2 1 5 3由于1的刪除,導致2的失衡,所以進行重平衡,即將3提升為根節點,2作為3的左孩子,5作為3的右孩子。

    3.失衡情況總結~

    ??從上面插入的四種情況,以及刪除的四種情況可以看出,無論是插入還是刪除,其失衡之后的形狀都是一樣的,所以調整的方式也是一樣的!

    ??因此,不管是插入還是刪除,我們都可以采用同樣的調整方式。

    ??在很多教程上,都是用單旋(LL 或RR型失衡 只旋轉一次)和雙旋(LR或RL型失衡 要旋轉兩次)來處理失衡的情況,如果你看過其他的教程,那么你必然對下面的圖有所熟悉。當然,你不熟悉,也沒關系,我們只看這四種情況對應的結果

    圖來自維基百科

    ??可以發現,無論是單旋還是雙旋,其調整之后的形狀毫無例外,都是這種結構。

    ??所以,我們可以只關注結果,不關心過程,無論哪種失衡情況,其調整之后的結構都是上面這種結構。因此就可以寫一個通用的調整函數,來專門負責失衡之后的調整。

    4.統一重平衡算法~

    ??幸運的是,鄧老師已經給出了解決方案。有了這種方法,你就再也不必為到底該左旋還是右旋而苦惱,也不必去記那種繁瑣的左右旋算法。

    (1)萬能的connect 3+4算法~

    ??將上面的四種情況,統一簡化成下面圖中的形式。無論是那種調整方式,最終都必然調整為這種形式。

    其中,b為調整后新子樹的樹根節點,a為b的左孩子,c為b的右孩子。 T0和T1分別為a的左右子樹,T2和T3分別為c的左右子樹。 ?? 對應的中序遍歷序列為{ T0, a, T1, b, T2, c, T3 } ??

    ??實際上,這一理解涵蓋了所有的單旋和雙旋情況。相應的重構過程,僅涉及局部的三個節點及其四棵子樹,故稱作“3 + 4”重構

    ??到這里,我相信你已經理解了在第三部分BST中所定義的connect34函數的作用了。

    connece34代碼~

    ??接下來只要將對應的節點按順序填入下面這個函數,就能實現重平衡。同時注意更新高度。

    ??在BST.h中定義的成員函數connect34,注意返回值為調整之后的根節點

    template<typename T> BinNode<T>* BST<T>::connect34(BinNode<T>* a, BinNode<T>* b, BinNode<T>* c,BinNode<T>* T1, BinNode<T>* T2, BinNode<T>* T3, BinNode<T>* T4) {a->_lchild = T1; if (T1)T1->_parent = a;a->_rchild = T2; if (T2)T2->_parent = a; this->updateHeight(a);c->_lchild = T3; if (T3)T3->_parent = c;c->_rchild = T4; if (T4)T4->_parent = c; this->updateHeight(c);b->_lchild = a; a->_parent = b;b->_rchild = c; c->_parent = b; this->updateHeight(b);return b; }

    ??下一步,問題就在于,如何確定 a b c T1 T2 T3 T4的順序?

    (2)萬能的rotateAt算法~

    ??觀察上面四種失衡情況,無論是哪種失衡情況,其失衡時,都必然涉及3個節點的位置變換。

    ??并且這三個節點,也一定為祖孫三代的關系。
    ??因此,不妨設最小的那個節點為v,其父親為p,其祖父為g。分四種情況,將v p g以及對應的孩子,放入connect34函數里面進行重平衡。

    rotateAt代碼~

    ??在BST.h中,我們定義了rotateAt算法,下面為其具體實現。對需要調整的節點,分四種情況,借助connect34函數,進行調整7個節點的相對位置。

    template<typename T> BinNode<T>* BST<T>::rotateAt(BinNode<T>* v) //返回調整后局部子樹根節點的位置 {if (v == nullptr) {printf("Error!"); exit(0);}//設定v的父親與祖父//視v、p和g相對位置分四種情況BinNode<T>* p = v->_parent; BinNode<T>* g = p->_parent;if (IsLChild(p)) {//Lif (IsLChild(v)) {//LLp->_parent = g->_parent;//向上連接return connect34(v, p, g, v->_lchild, v->_rchild, p->_rchild, g->_rchild);}else {//LRv->_parent = g->_parent;//向上連接return connect34(p, v, g, p->_lchild, v->_lchild, v->_rchild, g->_rchild);}}else {//Rif (IsRChild(v)) {//RRp->_parent = g->_parent;//向上連接return connect34(g, p, v, g->_lchild, p->_lchild, v->_lchild, v->_rchild);}else {//RLv->_parent = g->_parent;//向上連接return connect34(g, v, p, g->_lchild, v->_lchild, v->_rchild, p->_rchild);}} }

    讀者可以繼續通過這兩個圖來細細體會。

    (四)AVL的插入~

    ??在理解了AVL的重平衡原理之后,AVL的插入和刪除就也很容易理解了。

    在插入新的節點的時候,有一個現象,就是無論如何:1. 新節點的父親節點,一定不可能失衡; 2. 并且失衡的節點一定為該新節點的祖先節點; 3. 一旦其有一個祖先恢復了平衡,整顆AVL樹必將恢復平衡。

    插入代碼~

    ??像往常的樹的插入一樣,在插入之前,我們需要進行查找操作,如果存在這個節點,就不插入,如果不存在這個節點,就插入新的節點,并且得益于_hot節點(見第三部分BST中_hot節點的作用),我們能很快的將節點插入正確的位置,同時也更新了對應的父子節點指針。

    ??接下來就按照AVL插入新節點的性質,來寫出下面的代碼。并且在此處我們要用到FromParentTo算法(見第二部分BinTree),此算法的作用是獲取當前節點的父親的孩子的引用,即獲取當前節點的引用,哪怕當前節點里面的內容發生了變化,其作為指針的本身的地址不會發生變化,只是指針所指的地址發生了變化

    template<typename T> BinNode<T>* AVL<T>::insert(const T& data){//無論data在不在子樹中,返回值的_data均為dataBinNode<T>*& x = this->search(data);if (x)return x;x = new BinNode<T>(data,this->_hot);//創建新節點this->_size++;//更新規模for (BinNode<T>* g = this->_hot; g; g = g->_parent) {if (!IsAvlBalanced(g)) {//如果失衡//必須要提前將地址取好,不然g的里面的數據發生變動,就會造成指針亂指。BinNode<T>*& parent_child_Address = this->FromParentTo(g);parent_child_Address= this->rotateAt(tallerChild(tallerChild(g)));/*首先調用tallerChild函數,來確定到底旋轉哪一個g的孫子節點(選擇g的最高孩子的最高孩子作為旋轉節點)*在旋轉過程中,對g的孩子,g的孫子的左右旋情況,分四種情況進行判斷。并利用connect34函數,做快速重構*從而實現將失衡的g恢復正常平衡。并且rotateAt的返回值,就是重構后的對應子樹的根節點的位置,把這個返回值*作為原來g的父親的孩子,即重新連接重構后的子樹與原來的子樹。并且在connect34過程中,對樹的高度也進行了更新。所以不必再度更新。*/break;//一旦發生了重構,就不需要對后續的祖先進行高度更新和重構了。}else {this->updateHeight(g);//未失衡,只需更新g的高度,不需要更新所有高度。}}return x; }

    ??并且在插入算法中,我們用到了tallerChild函數,這個函數是獲取當前節點的最高孩子節點。我們需要用這個函數,來獲取傳到rotateAt函數里面節點。

    tallerChild函數~

    ??顧名思義,獲取當前節點的最高的孩子。

    /*期望c++20可以支持,auto compareResult = stature(x->_lchild) <=> stature(x->_rchild);*/ template<typename T> inline BinNode<T>*& AVL<T>::tallerChild(BinNode<T>*& x){int lHeight = stature(x->_lchild);int rHeight = stature(x->_rchild);if (lHeight > rHeight) {return x->_lchild;}else if (lHeight < rHeight) {return x->_rchild;}else {//如果左右高度相等,則按父親是左孩子還是右孩子,來返回對應的左右孩子return (IsLChild(x) ? x->_lchild : x->_rchild);} }

    效率分析~

    ??該算法首先按照二叉搜索樹的常規算法,在O(logn)時間內插入新節點x。
    ??既然原樹是平衡的,故至多檢查O(logn)個節點即可確定失衡節點;如有必要,只需要進行一次重構,即可使局部乃至全樹恢復平衡。
    ??由此可見,AVL樹的節點插入操作可以在O(logn)時間內完成。

    (五)AVL的刪除~

    在刪除新的節點的時候,有一個現象,就是無論如何: 1. 第一個失衡的節點,可能是父親節點。 2. 每一次失衡,都必然只有一個祖先失衡,失衡的也只可能是祖先節點,不可能多個祖先同時失衡 3. 一個祖先修復平衡后,可能接下來導致下一個祖先也失衡,極端條件下,可能要重平衡多次。

    刪除代碼~

    ??AVL的刪除的大體步驟跟BST的刪除十分類似,只是刪除之后,要進行修復平衡。因此需要借助在第三部分BST中定義的removeAt刪除靜態函數(建議理解了這個函數再來看AVL的刪除)。

    ??AVL刪除的重平衡算法和插入的重平衡算法類似,只是對于祖先節點處理方式不一樣,在插入算法中,一旦一個祖先恢復平衡,其他祖先就不需要進行平衡的檢測了。而刪除算法中,哪怕這個節點恢復了平衡,也要對其父親進行平衡的檢測

    ??只有當前節點是平衡的,并且高度沒有發生變化時,重平衡才大功告成。

    template<typename T> bool AVL<T>::remove(const T& data) {BinNode<T>*& x = this->search(data);if (!x)return false;//如果不存在,返回falseremoveAt(x, this->_hot);//刪除此節點,并更新_hot值this->_size--;//更新規模for (BinNode<T>* g = this->_hot; g; g = g->_parent) {if (!IsAvlBalanced(g)) {//如果失衡BinNode<T>*& parent_child_Address = this->FromParentTo(g);//先記錄之前的父親節點的孩子指針parent_child_Address = this->rotateAt(tallerChild(tallerChild(g)));//將孩子指針指向新的子樹根節點g = parent_child_Address;//更新g,g此時必然是處于平衡狀態}else {int gHeight = g->_height;if (gHeight == this->updateHeight(g)) {//沒失衡也要檢查高度,祖先高度沒變,則后序祖先也不需要進行更新。break;} }}return true;//刪除成功 }

    效率分析~

    ??較之插入操作,刪除操作可能需在重平衡方面多花費一些時間。不過,既然需做重平衡的節點都是被刪除節點的祖先,故重平衡過程累計只需不過O(logn)時間。
    ??綜合各方面的消耗,AVL樹的節點刪除操作總體的時間復雜度依然是O(logn)。

    五、完整AVL.h~

    #pragma once #include "BST.h"namespace mytree {template<typename T = int>class AVL :public BST<T> {protected:using BinNodePtr = BinNode<T>*;public:BinNodePtr insert(const T& data)override;//插入(重寫)bool remove(const T& data)override;//刪除(重寫)protected:static constexpr bool IsAvlBalanced(const BinNodePtr& x) {//判斷是否平衡int BalanceFactor = stature(x->_lchild) - stature(x->_rchild);return (-2 < BalanceFactor && BalanceFactor < 2);}static BinNodePtr& tallerChild(BinNode<T>*& x);//更高的孩子};//class AVLtemplate<typename T>BinNode<T>* AVL<T>::insert(const T& data){//無論data在不在子樹中,返回值的_data均為dataBinNode<T>*& x = this->search(data);if (x)return x;x = new BinNode<T>(data,this->_hot);//創建新節點this->_size++;//更新規模for (BinNode<T>* g = this->_hot; g; g = g->_parent) {if (!IsAvlBalanced(g)) {//如果失衡//必須要提前將地址取好,不然g的里面的數據發生變動,就會造成指針亂指。BinNode<T>*& parent_child_Address = this->FromParentTo(g);parent_child_Address= this->rotateAt(tallerChild(tallerChild(g)));/*首先調用tallerChild函數,來確定到底旋轉哪一個g的孫子節點(選擇g的最高孩子的最高孩子作為旋轉節點)*在旋轉過程中,對g的孩子,g的孫子的左右旋情況,分四種情況進行判斷。并利用connect34函數,做快速重構*從而實現將失衡的g恢復正常平衡。并且rotateAt的返回值,就是重構后的對應子樹的根節點的位置,把這個返回值*作為原來g的父親的孩子,即重新連接重構后的子樹與原來的子樹。并且在connect34過程中,對樹的高度也進行了更新。所以不必再度更新。*/break;//一旦發生了重構,就不需要對后續的祖先進行高度更新和重構了。}else {this->updateHeight(g);//未失衡,只需更新g的高度,不需要更新所有高度。}}return x;}template<typename T>bool AVL<T>::remove(const T& data){BinNode<T>*& x = this->search(data);if (!x)return false;//如果不存在,返回falseremoveAt(x, this->_hot);//刪除此節點,并更新_hot值this->_size--;//更新規模for (BinNode<T>* g = this->_hot; g; g = g->_parent) {if (!IsAvlBalanced(g)) {//如果失衡BinNode<T>*& parent_child_Address = this->FromParentTo(g);//先記錄之前的父親節點的孩子指針parent_child_Address = this->rotateAt(tallerChild(tallerChild(g)));//將孩子指針指向新的子樹根節點g = parent_child_Address;//更新g,g此時必然是處于平衡狀態}else {int gHeight = g->_height;if (gHeight == this->updateHeight(g)) {//沒失衡也要檢查高度,祖先高度沒變,則后序祖先也不需要進行更新。break;} }}return true;//刪除成功}/*期望c++20可以支持,auto compareResult = stature(x->_lchild) <=> stature(x->_rchild);*/template<typename T>inline BinNode<T>*& AVL<T>::tallerChild(BinNode<T>*& x){int lHeight = stature(x->_lchild);int rHeight = stature(x->_rchild);if (lHeight > rHeight) {return x->_lchild;}else if (lHeight < rHeight) {return x->_rchild;}else {//如果左右高度相等,則按父親是左孩子還是右孩子,來返回對應的左右孩子return (IsLChild(x) ? x->_lchild : x->_rchild);}}}//namespace mytree

    六、測試代碼~

    1.插入測試代碼~

    #include<iostream> #include "AVL.h" using namespace std; using namespace mytree;template<typename BinNodePtr> void visitprint(BinNodePtr x) {cout << x->_data; }int main() {AVL<int>* avl = new AVL<int>;for (int i = 0; i < 10; ++i) {avl->insert(i);}avl->travLevel(visitprint<BinNode<int>*>);cout << endl;avl->travPre(visitprint<BinNode<int>*>);cout << endl;avl->travIn(visitprint<BinNode<int>*>);cout << endl;avl->travPost(visitprint<BinNode<int>*>);cout << endl;delete avl;return 0; } 3170258469 3102754689 0123456789 0214659873

    2.插入測試圖示~

    3.刪除測試代碼~

    #include<iostream> #include "AVL.h" using namespace std; using namespace mytree;template<typename BinNodePtr> void visitprint(BinNodePtr x) {cout << x->_data; }int main() {AVL<int>* avl = new AVL<int>;for (int i = 0; i < 10; ++i) {avl->insert(i);}avl->travLevel(visitprint<BinNode<int>*>);cout << endl;avl->travPre(visitprint<BinNode<int>*>);cout << endl;avl->travIn(visitprint<BinNode<int>*>);cout << endl;avl->travPost(visitprint<BinNode<int>*>);cout << endl<<endl;for (int i = 0; i < 10; ++i) {avl->remove(i);avl->travIn(visitprint<BinNode<int>*>);cout << endl;}delete avl;return 0; } 3170258469 3102754689 0123456789 0214659873123456789 23456789 3456789 456789 56789 6789 789 89 9

    4.刪除測試圖示~

    七、后序文章鏈接~

  • 基本二叉樹節點,通用函數 二叉樹節點
  • 基本二叉樹類的定義和實現 二叉樹基類
  • BST(二叉搜索樹的實現) BST
  • AVL(二叉平衡搜索樹的實現)AVL
  • B樹的實現(如果你只想了解B樹,可以跳過所有章節,直接看B樹)B樹
  • 紅黑樹的實現 RedBlack
  • 學一個東西,不知道其道理,不高明!

    總結

    以上是生活随笔為你收集整理的真c++ 从二叉树到红黑树(4)之二叉平衡搜索树AVL的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。