中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

教育培訓(xùn)網(wǎng)站制作百度2023免費(fèi)下載

教育培訓(xùn)網(wǎng)站制作,百度2023免費(fèi)下載,免費(fèi)域名注冊(cè)推薦,wordpress 上線到centos高階數(shù)據(jù)結(jié)構(gòu)相關(guān)知識(shí)點(diǎn)可以通過(guò)點(diǎn)擊以下鏈接進(jìn)行學(xué)習(xí)一起加油!二叉搜索樹 大家好,這里是店小二!今天我們將深入探討高階數(shù)據(jù)結(jié)構(gòu)中的AVL樹。AVL樹是一種自平衡的二叉搜索樹,可以看作是對(duì)傳統(tǒng)二叉搜索樹的優(yōu)化版本。如果你對(duì)數(shù)據(jù)結(jié)…

請(qǐng)?zhí)砑訄D片描述

高階數(shù)據(jù)結(jié)構(gòu)相關(guān)知識(shí)點(diǎn)可以通過(guò)點(diǎn)擊以下鏈接進(jìn)行學(xué)習(xí)一起加油!
二叉搜索樹

大家好,這里是店小二!今天我們將深入探討高階數(shù)據(jù)結(jié)構(gòu)中的AVL樹。AVL樹是一種自平衡的二叉搜索樹,可以看作是對(duì)傳統(tǒng)二叉搜索樹的優(yōu)化版本。如果你對(duì)數(shù)據(jù)結(jié)構(gòu)感興趣,快拿出你的小本本,和我們一起開始這段探索之旅吧!

請(qǐng)?zhí)砑訄D片描述
Alt
🌈個(gè)人主頁(yè):是店小二呀
🌈C語(yǔ)言專欄:C語(yǔ)言
🌈C++專欄: C++
🌈初階數(shù)據(jù)結(jié)構(gòu)專欄: 初階數(shù)據(jù)結(jié)構(gòu)
🌈高階數(shù)據(jù)結(jié)構(gòu)專欄: 高階數(shù)據(jù)結(jié)構(gòu)
🌈Linux專欄: Linux

🌈喜歡的詩(shī)句:無(wú)人扶我青云志 我自踏雪至山巔 請(qǐng)?zhí)砑訄D片描述

文章目錄

  • 前文
    • 一、AVL樹概念
  • 二、AVL樹實(shí)現(xiàn)
    • 2.1 AVL樹節(jié)點(diǎn)的定義 (成員默認(rèn)訪問(wèn)公有)
    • 2.2 AVL樹查找邏輯
    • 2.3 AVL樹插入邏輯
  • 三、AVL的旋轉(zhuǎn)(重點(diǎn))
    • 3.1 選用抽象圖探討AVL旋轉(zhuǎn)
    • 3.2 單旋問(wèn)題
      • 3.2.1 新節(jié)點(diǎn)插入較高左子樹的左側(cè)--左左:右單旋
      • 3.2.2 新節(jié)點(diǎn)插入較高右子樹的右側(cè)--右右:左單旋
    • 3.3 雙旋解決問(wèn)題
      • 3.3.1 新節(jié)點(diǎn)插入較高左子樹的右側(cè)--左右:先左單旋再右單旋
      • 3.3.2 根據(jù)結(jié)論修改AVL樹節(jié)點(diǎn)平衡因子
      • 3.3.3 新節(jié)點(diǎn)插入較高右子樹的左側(cè)---右左:先右單旋再左單旋
      • 3.3.4 小總結(jié)
  • 四、AVL樹的驗(yàn)證
    • 4.1 驗(yàn)證其為二叉搜索樹
    • 4.2 驗(yàn)證其為平衡樹
  • 五、AVL樹的刪除(了解 )
  • 六、AVL樹的性能
  • 七、AVLTree.h

前文

關(guān)于上篇二叉搜索樹性能那塊,探討了二叉搜索樹雖然可以縮短查找的效率,但如果數(shù)據(jù)有序或接近有序二叉搜索樹將退化為單支樹,查找元素相當(dāng)于在順序表中搜索元素,效率低下。

因此,兩位俄羅斯的數(shù)學(xué)家G.M.Adelson-VelskiiE.M.Landis在1962年發(fā)明了一種解決上述問(wèn)題的方法:當(dāng)向二叉搜索樹中插入新結(jié)點(diǎn)后,如果能保證每個(gè)結(jié)點(diǎn)的左右子樹高度之差的絕對(duì)值不超過(guò)1(需要對(duì)樹中的結(jié)點(diǎn)進(jìn)行調(diào)整),即可降低樹的高度,從而減少平均搜索長(zhǎng)度,按照這種規(guī)則形成的二叉搜索樹為AVL樹,保持著嚴(yán)格的平衡。

一、AVL樹概念

一棵AVL樹或者是空樹,或者是具有以下性質(zhì)的二叉搜索樹:

  • 它的左右子樹都是AVL樹
  • 左右子樹高度之差(簡(jiǎn)稱平衡因子)的絕對(duì)值不超過(guò)1(-1/0/1)
  • 平衡因子并不是必須,只是他的一種實(shí)現(xiàn)方式

在這里插入圖片描述
在這里插入圖片描述

如果一棵二叉搜索樹是高度平衡的,它就是AVL樹。如果它有n個(gè)結(jié)點(diǎn),其高度可保持在logn,搜索時(shí)間復(fù)雜度O(logn)

平衡因子計(jì)算:

  • 平衡因子 = 右子樹高度 - 左子樹高度

二、AVL樹實(shí)現(xiàn)

2.1 AVL樹節(jié)點(diǎn)的定義 (成員默認(rèn)訪問(wèn)公有)

template<class K, class V>struct AVLTreeNode{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;pair<K, V> _kv;int _bf;//主要類型AVLTreeNode(const pair<K, V> & kv):_left(nullptr),_right(nullptr),_parent(nullptr),_kv(kv),_bf(0){}};

AVL樹每個(gè)結(jié)構(gòu)存儲(chǔ)一個(gè)pair<K, V>對(duì)象,其中需要parent指針目的是為了方便訪問(wèn)當(dāng)前節(jié)點(diǎn)的上一個(gè)節(jié)點(diǎn)。

考慮到AVLTreeNode<K ,V>書寫麻煩,使用typedef進(jìn)行類型重定義typedef AVLTreeNode<K, V> Node;

2.2 AVL樹查找邏輯

	Node* Find(const K& key){//按照搜索樹Node* cur = _root;while (cur){if (key > cur->_kv.first){cur = cur->_right;}else if (key < cur->_kv.first){cur = cur->_left;}else{//返回當(dāng)前節(jié)點(diǎn)的指針return cur;}}//防止意外發(fā)生。return nullptr;}

本質(zhì)上來(lái)說(shuō)AVL樹屬于二叉搜索樹,關(guān)于cur->_kv.first是cur通過(guò)指針去訪問(wèn)Node類中類型為pair<K, V>對(duì)象的_kv。通過(guò)set與map簡(jiǎn)單學(xué)習(xí)。可以得知pair內(nèi)部實(shí)現(xiàn)邏輯,_這里的kv.first中first是K類型的對(duì)象。同時(shí)AVL也是二叉樹搜索樹,查找邏輯當(dāng)然是使用二叉搜索樹的邏輯。

2.3 AVL樹插入邏輯

既然AVL也是二叉搜索樹,那么插入邏輯也是一樣的,不同在于需要進(jìn)行平衡因子的調(diào)正。(平衡因子 = 右子樹高度 - 左子樹高度)

當(dāng)插入節(jié)點(diǎn)結(jié)束后,對(duì)插入節(jié)點(diǎn)的父親節(jié)點(diǎn)進(jìn)行平衡因子的修改。當(dāng)對(duì)于父親節(jié)點(diǎn)達(dá)到特定值會(huì)對(duì)應(yīng)不同的情況,不斷利用parent向上調(diào)整父親節(jié)點(diǎn)的平衡因子。

通過(guò)例圖去分析,當(dāng)父親平衡因子到達(dá)特定值對(duì)應(yīng)不同情況:

第一張:當(dāng)parent平衡因子從1或-1變到0

在這里插入圖片描述

第二張:這里出現(xiàn)兩種情況,parent平衡因子從0變到1或-1,parent平衡因子從1或-1變到2或-2。只有從0變到1或-1,沒(méi)有從2或-2變成1或-1,因?yàn)楫?dāng)parent平衡因子絕對(duì)值超過(guò)1時(shí),已經(jīng)出現(xiàn)問(wèn)題,需要進(jìn)行調(diào)正

在這里插入圖片描述

具體說(shuō)明:

  1. 按照搜索樹規(guī)則插入
  2. 某個(gè)父親節(jié)點(diǎn)的平衡因子
    • 插入父親的左孩子,父親平衡因子–
    • 插入父親的右孩子,父親平衡因子++
while (parent)
{//規(guī)矩平衡因子的規(guī)則,是根據(jù)特性和下面代碼得來(lái)的if (parent->_left == cur){parent->_bf--;}else if (parent->_right == cur){parent->_bf++;}//判斷是否回到父親節(jié)點(diǎn)改動(dòng)if (parent->_bf == 0){//沒(méi)有啥問(wèn)題,可以跳出程序break;}else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = parent->_parent;}//出現(xiàn)問(wèn)題,這種情況是由情況二變化過(guò)來(lái)的,那么就是說(shuō),cur和parent向上移動(dòng)了else if (parent->_bf == 2 || parent->_bf == -2{//.............}
}

理解:

在節(jié)點(diǎn)插入后,需要進(jìn)行平衡因子的更新。更新順序是從下到上,結(jié)合著父親節(jié)點(diǎn)平衡因子進(jìn)行判斷是否需要繼續(xù)向上更新。

根據(jù)判斷更新父親的平衡因子狀況進(jìn)行處理(該平衡因子更新完后):

  • 父親平衡因子 == 0,父親所在子樹高度不變,不再繼續(xù)往上更新,插入結(jié)束
  • 父親平衡因子 == 1 or -1, 父親所在子樹高度變了,繼續(xù)往上更新上面節(jié)點(diǎn)的平衡因子
  • 父親平衡因子 == 2 or -2, 父親所在的子樹已經(jīng)不平衡了,需要旋轉(zhuǎn)處理

三、AVL的旋轉(zhuǎn)(重點(diǎn))

如果在一顆原本是平衡的AVL樹中插入一個(gè)新節(jié)點(diǎn),可能造成不平衡,此時(shí)必須調(diào)整樹的結(jié)構(gòu)使之平衡化。根據(jù)節(jié)點(diǎn)插入位置的不同,AVL樹的旋轉(zhuǎn)分為四種:

在這里插入圖片描述

這里可以將前面兩種歸為單旋進(jìn)行處理,而后面兩種需要通過(guò)雙旋進(jìn)行處理。

提前說(shuō)明:一個(gè)AVL樹有多個(gè)AVL樹或者說(shuō)一個(gè)復(fù)雜的AVL樹是由許多個(gè)簡(jiǎn)單的AVL樹進(jìn)行組合而成的。那么如果插入一個(gè)節(jié)點(diǎn)導(dǎo)致AVL樹失去平衡,這里AVL樹指以插入節(jié)點(diǎn)的父親節(jié)點(diǎn)為根節(jié)點(diǎn)的子AVL樹。遵守一個(gè)有問(wèn)題解決問(wèn)題,如果只是這一課AVL樹有問(wèn)題,就解決這顆AVL樹,正常的AVL樹我們是不要去過(guò)多的進(jìn)行處理。

根據(jù)說(shuō)明,如果將一整棵AVL樹全部拆分進(jìn)行研究,不同節(jié)點(diǎn)插入的位置很多選擇,情況有很多種,難以全部羅列出來(lái),而且沒(méi)有必要,如果將一顆有問(wèn)題AVL樹治好,就可以將任何一顆AVL樹治好,所以這邊采用使用抽象圖進(jìn)行分析。

3.1 選用抽象圖探討AVL旋轉(zhuǎn)

其中使用a、b、c子AVL樹及其高度設(shè)置為h

在這里插入圖片描述

在這里插入圖片描述

抽象圖中的抽象的AVL樹平衡因子這里不用看的,目前羅列的情況是可以包含這里的,這里小部分就是大部分調(diào)正平衡因子的過(guò)程,意味著這部分也可以是抽象AVL樹中的情況按照當(dāng)前處理已經(jīng)進(jìn)行了調(diào)整。

3.2 單旋問(wèn)題

使用單旋場(chǎng)景:parent->_bf == 2 && cur->_bf == 1或者parent->_bf == -2 && cur->_bf == -1

3.2.1 新節(jié)點(diǎn)插入較高左子樹的左側(cè)–左左:右單旋

場(chǎng)景:parent->_ bf == -2 && cur->_bf == -1

在這里插入圖片描述

在這里插入圖片描述

具體解析旋轉(zhuǎn)步驟:

目前AVL樹是平衡的,當(dāng)插入新節(jié)點(diǎn)30到左子樹中,左子樹高度加一層,導(dǎo)致以60為根的子AVL樹失去平衡。為了使得平衡,意味著節(jié)點(diǎn)60的右子樹也需要增加一層,那么將60節(jié)點(diǎn)成為30節(jié)點(diǎn)的左孩子,同時(shí)原本30節(jié)點(diǎn)的左孩子和60節(jié)點(diǎn)成為30節(jié)點(diǎn)的左孩子的高度相同,那么將原本30節(jié)點(diǎn)的左孩子成為60節(jié)點(diǎn)有孩子。這里保證了30節(jié)點(diǎn)原本左孩子一定是小于60節(jié)點(diǎn)的。更新節(jié)點(diǎn)的平衡因子即可,簡(jiǎn)單概況就是30 < b子樹 < 60 < c子樹

旋轉(zhuǎn)過(guò)程中,有以下幾點(diǎn)情況需要考慮:

  1. 30節(jié)點(diǎn)的右孩子可能存在,也可能不存在
  2. 60可能是根節(jié)點(diǎn),也可能是子樹
    • 如果是根節(jié)點(diǎn),旋轉(zhuǎn)完成后,要更新根節(jié)點(diǎn)
    • 如果是子樹,可能是某個(gè)節(jié)點(diǎn)的左子樹,也可能是右子樹
void RotateR(Node* parent)
{Node* SubL = parent->_left;Node* SubLR = SubL->_right;parent->_left = SubLR;if (SubLR)SubLR->_parent = parent;SubL->_right = parent;Node* ppNode = parent->_parent;parent->_parent = subL;if (parent == _root){SubL = _root;SubL->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = SubL;}else if(ppNode->_right == parent){ppNode->_right = SubL;}SubL->_parant = ppNode;}SubL->_bf = 0;parent->_bf = 0;
}

通過(guò)旋轉(zhuǎn)使得不平衡AVL樹得到調(diào)整,這里不需要考慮向上更新平衡因子。從抽象圖中可以得出旋轉(zhuǎn)后結(jié)論,直接使用結(jié)論修改平衡因子就行。

3.2.2 新節(jié)點(diǎn)插入較高右子樹的右側(cè)–右右:左單旋

場(chǎng)景:parent->_ bf == 2 && cur->_bf == 1

在這里插入圖片描述

這里和右單旋是差不多的,具體流程可以去看上述和代碼分析

在這里插入圖片描述

void RotateL(Node* parent)
{Node* SubR = parent->_right;Node* SubRL = SubR->_left;parent->_right = SubRL;if (SubRL)SubR->_parent = parent;SubR->_left = parent;Node* ppNode = parent->_parent;parent->_parent = subR;if (parent == _root){SubR = _root;SubR->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = SubR;}else if (ppNode->_right == parent){ppNode->_right = SubR;}SubR->_parant = ppNode;}SubR->_bf = 0;parent->_bf = 0;
}

3.3 雙旋解決問(wèn)題

如果出現(xiàn)了這種if (parent->_bf == 2 || cur->_bf == -1), if (parent->_bf == -2 || cur->_bf == 1)普通單旋是不能解決問(wèn)題的,需要使用到雙旋。

如果使用單旋的話是沒(méi)有多大作用的,做無(wú)用功。我們使用單旋處理的情況是一邊獨(dú)高,而不是那邊高,這邊高。對(duì)此可以先對(duì)內(nèi)部旋轉(zhuǎn)變成單獨(dú)一邊高,再使用單旋進(jìn)行調(diào)整AVL樹。

在這里插入圖片描述

3.3.1 新節(jié)點(diǎn)插入較高左子樹的右側(cè)–左右:先左單旋再右單旋

場(chǎng)景:parent->_bf == -2 && cur->_bf == 1

在這里插入圖片描述
在這里插入圖片描述

這里可以直接復(fù)用實(shí)現(xiàn)好單旋的接口,但是需要對(duì)平衡因子進(jìn)行調(diào)整,這里平衡因子可以通過(guò)結(jié)論直接修改。

3.3.2 根據(jù)結(jié)論修改AVL樹節(jié)點(diǎn)平衡因子

通過(guò)圖中對(duì)于不同情況的分析,對(duì)于修改平衡因子的結(jié)果是根據(jù)SubLR平衡因子特殊值決定的。b、c分別給誰(shuí),會(huì)影響平衡因子的分配。

在這里插入圖片描述

3.3.3 新節(jié)點(diǎn)插入較高右子樹的左側(cè)—右左:先右單旋再左單旋

場(chǎng)景:parent->_bf == 2 && cur->_bf == -1

在這里插入圖片描述

這里還是需要根據(jù)60這塊的平衡因子去判斷的,b c分別給誰(shuí),會(huì)影響平衡因子的分配。左邊新增兩次旋轉(zhuǎn)給到右邊,右邊新增兩次旋轉(zhuǎn)給到左邊,通過(guò)結(jié)論最后修改平衡因子。

void RotateRL(Node* parent)
{Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(subR);RotateL(parent);subRL->_bf = 0;if (bf == 1){subR->_bf = 0;parent->_bf = -1;}else if (bf == -1){parent->_bf = 0;subR->_bf = 1;}else{parent->_bf = 0;subR->_bf = 0;}}void RotateLR(Node* parent)
{Node* SubL = parent->_left;Node* SubLR = SubL->_right;int _bf = SubLR->_bf;RotateL(parent->_left);RotateR(parent);if (_bf == 0){parent->_bf = 0;SubL->_bf = 0;SubLR->_bf = 0;}else if (_bf == 1){parent->_bf = 0;SubL->_bf = -1;SubLR->_bf = 0;}else if (_bf == -1){parent->_bf = 1;SubL->_bf = 0;SubLR->_bf = 0;}else{assert(false);}
}

3.3.4 小總結(jié)

假如以pParent為根的子樹不平衡,即pParent的平衡因子為2或者-2,分以下情況考慮 :

  1. pParent的平衡因子為2,說(shuō)明pParent的右子樹高,設(shè)pParent的右子樹的根為pSubR
  • 當(dāng)pSubR的平衡因子為1時(shí),執(zhí)行左單旋
  • 當(dāng)pSubR的平衡因子為-1時(shí),執(zhí)行右左雙旋
  1. pParent的平衡因子為-2,說(shuō)明pParent的左子樹高,設(shè)pParent的左子樹的根為pSubL
  • 當(dāng)pSubL的平衡因子為-1是,執(zhí)行右單旋
  • 當(dāng)pSubL的平衡因子為1時(shí),執(zhí)行左右雙旋

旋轉(zhuǎn)完成后,原pParent為根的子樹個(gè)高度降低,已經(jīng)平衡,不需要再向上更新

四、AVL樹的驗(yàn)證

AVL樹是在二叉搜索樹的基礎(chǔ)上加入了平衡性的限制,因此要驗(yàn)證AVL樹,可以分為兩步:驗(yàn)證是否為二叉搜索樹,驗(yàn)證是否為平衡樹

4.1 驗(yàn)證其為二叉搜索樹

如果中序遍歷可得到一個(gè)有序的序列,就說(shuō)明為二叉搜索樹

void InOder()
{_InOder(_root);cout << endl;
}private:
void _InOder(Node* _root)
{if (_root == nullptr){return;}InOder(_root->_left);cout << _root->_kv.first << " " << _root->_kv.second << endl;InOder(_root->_right);
}

這里將中序遍歷實(shí)現(xiàn)邏輯封裝到私有成員函數(shù)中隱藏它的具體實(shí)現(xiàn)細(xì)節(jié),使得外部用戶無(wú)法直接訪問(wèn)該函數(shù),提高了代碼的安全性和可維護(hù)性,符合面向?qū)ο缶幊痰姆庋b性原則。這里外部訪問(wèn)中序遍歷接口,只是傳遞了節(jié)點(diǎn)指針的副本,而不修改任何節(jié)指針的實(shí)際值。

4.2 驗(yàn)證其為平衡樹

規(guī)則:

  • 每個(gè)節(jié)點(diǎn)子樹高度差的絕對(duì)值不超過(guò)1(注意節(jié)點(diǎn)種種那個(gè)如果沒(méi)有平衡因子)
  • 節(jié)點(diǎn)的平衡因子是否計(jì)算正確
bool IsBalance()
{return _IsBalance(_root);
}int Height()
{return _Height(_root);
}int Size()
{return _Size(_root);
}private:
int _Size(Node* root)
{return root == nullptr ? 0 : _Size(root->_left) + _Size(root->_right) + 1;
}int _Height(Node* root)
{if (root == nullptr)return 0;return max(_Height(root->_left), _Height(root->_right)) + 1;
}bool _IsBalance(Node* root)
{if (root == nullptr)return true;int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);// 不平衡if (abs(leftHeight - rightHeight) >= 2){cout << root->_kv.first << endl;return false;}// 順便檢查一下平衡因子是否正確if (rightHeight - leftHeight != root->_bf){cout << root->_kv.first << endl;return false;}return _IsBalance(root->_left)&& _IsBalance(root->_right);
}void _InOder(Node* _root)
{if (_root == nullptr){return;}InOder(_root->_left);cout << _root->_kv.first << " " << _root->_kv.second << endl;InOder(_root->_right);
}

五、AVL樹的刪除(了解 )

因?yàn)锳VL樹也是二叉搜索樹,可按照二叉搜索樹的方式將節(jié)點(diǎn)刪除,然后再更新平衡因子,只不錯(cuò)與刪除不同的時(shí),刪除節(jié)點(diǎn)后的平衡因子更新,最差情況下一直要調(diào)整到根節(jié)點(diǎn)的位置 ,這里調(diào)正平衡因子的邏輯就需要反過(guò)來(lái),同時(shí)參考下二叉搜索樹的刪除操作。

六、AVL樹的性能

AVL樹是一棵絕對(duì)平衡的二叉搜索樹,其要求每個(gè)節(jié)點(diǎn)的左右子樹高度差的絕對(duì)值都不超過(guò)1,這樣可以保證查詢時(shí)高效的時(shí)間復(fù)雜度,即O(log^n^)`。但是如果要對(duì)AVL樹做一些結(jié)構(gòu)修改的操作,性能非常低下。

插入時(shí)要維護(hù)其絕對(duì)平衡,旋轉(zhuǎn)的次數(shù)比較多,更差的是在刪除時(shí),有可能一直要讓旋轉(zhuǎn)持續(xù)到根的位置。因此:如果需要一種查詢高效且有序的數(shù)據(jù)結(jié)構(gòu),而且數(shù)據(jù)的個(gè)數(shù)為靜態(tài)的(即不會(huì)改變),可以考慮AVL樹,但一個(gè)結(jié)構(gòu)經(jīng)常修改,就不太適合

補(bǔ)充調(diào)式小技巧:

void TestAVLTree1()
{//int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };int a[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };AVLTree<int, int> t1;for (auto e : a){/*if (e == 4){int i = 0;}*/// 1、先看是插入誰(shuí)導(dǎo)致出現(xiàn)的問(wèn)題// 2、打條件斷點(diǎn),畫出插入前的樹// 3、單步跟蹤,對(duì)比圖一一分析細(xì)節(jié)原因t1.Insert({e,e});cout <<"Insert:"<< e<<"->"<< t1.IsBalance() << endl;}t1.InOrder();cout << t1.IsBalance() << endl;
}

七、AVLTree.h

#pragma once
#include <assert.h>
#include <iostream>
using namespace std;//設(shè)置默認(rèn)權(quán)限為公用的結(jié)構(gòu)體
template<class K, class V>struct AVLTreeNode{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;pair<K, V> _kv;int _bf;//主要類型AVLTreeNode(const pair<K, V>& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _kv(kv), _bf(0){}};template<class K, class V>class AVLTree{typedef AVLTreeNode<K, V> Node;public:Node* Find(const K& key){//按照搜索樹Node* cur = _root;while (cur){if (cur->_kv.first < key){cur = cur->_right;}else if (cur->_kv.first > key){cur = cur->_left;}else{//返回當(dāng)前節(jié)點(diǎn)的指針return cur;}}return nullptr;}bool Insert(const pair<K, V>& kv){if (_root == nullptr){_root = new Node(kv);return true;}//也是查找需要插入的地方,進(jìn)行插入Node* parent = nullptr;Node* cur = _root;//目的就是讓cur走到合適的空位置while (cur){if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else{assert(!cur);}}//需要將這個(gè)節(jié)點(diǎn)連接起來(lái)cur = new Node(kv);cur->_parent = parent;if (parent->kv.first > cur->_kv.first){parent->_left = cur;}else if (parent->kv.first < cur->_kv.first){parent->_right = cur;}//上述完成了插入的邏輯,調(diào)正平衡因子while (parent){//平衡因子的規(guī)則if (parent->_left == cur){parent->_bf--;}else if (parent->_right == cur){parent->_bf++;}//判斷是否回到父親節(jié)點(diǎn)改動(dòng)if (parent->_bf == 0){//沒(méi)有啥問(wèn)題,可以跳出程序break;}else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = parent->_parent;}//出現(xiàn)問(wèn)題,這種情況是由情況二變化過(guò)來(lái)的,那么就是說(shuō),cur和parent向上移動(dòng)了else if (parent->_bf == 2 || parent->_bf == -2){//這里根據(jù)規(guī)律,去固定改變平衡因子if (parent->_bf == 2 && cur->_bf == 1){RotateL(parent);}if (parent->_bf == -2 && cur->_bf == -1){RotateR(parent);}//雙旋if (parent->_bf == 2 &&  cur->_bf == -1){RotateRL(parent);}if (parent->_bf == -2 && cur->_bf == 1){RotateLR(parent);}break;}else{assert(false);}}}void RotateR(Node* parent){Node* SubL = parent->_left;Node* SubLR = SubL->_right;parent->_left = SubLR;if (SubLR)SubLR->_parent = parent;SubL->_right = parent;Node* ppNode = parent->_parent;parent->_parent = SubL;if (parent == _root){SubL = _root;SubL->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = SubL;}else if (ppNode->_right == parent){ppNode->_right = SubL;}SubL->_parant = ppNode;}SubL->_bf = 0;parent->_bf = 0;}void RotateL(Node* parent){Node* SubR = parent->_right;Node* SubRL = SubR->_left;parent->_right = SubRL;if (SubRL)SubR->_parent = parent;SubR->_left = parent;Node* ppNode = parent->_parent;parent->_parent = SubR;if (parent == _root){SubR = _root;SubR->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = SubR;}else if (ppNode->_right == parent){ppNode->_right = SubR;}SubR->_parant = ppNode;}SubR->_bf = 0;parent->_bf = 0;}void RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(subR);RotateL(parent);subRL->_bf = 0;if (bf == 1){subR->_bf = 0;parent->_bf = -1;}else if (bf == -1){parent->_bf = 0;subR->_bf = 1;}else{parent->_bf = 0;subR->_bf = 0;}}void RotateLR(Node* parent){Node* SubL = parent->_left;Node* SubLR = SubL->_right;int _bf = SubLR->_bf;RotateL(parent->_left);RotateR(parent);if (_bf == 0){parent->_bf = 0;SubL->_bf = 0;SubLR->_bf = 0;}else if (_bf == 1){parent->_bf = 0;SubL->_bf = -1;SubLR->_bf = 0;}else if (_bf == -1){parent->_bf = 1;SubL->_bf = 0;SubLR->_bf = 0;}else{assert(false);}}void InOder(){_InOder(_root);cout << endl;}bool IsBalance(){return _IsBalance(_root);}int Height(){return _Height(_root);}int Size(){return _Size(_root);}private:int _Size(Node* root){return root == nullptr ? 0 : _Size(root->_left) + _Size(root->_right) + 1;}int _Height(Node* root){if (root == nullptr)return 0;return max(_Height(root->_left), _Height(root->_right)) + 1;}bool _IsBalance(Node* root){if (root == nullptr)return true;int leftHeight = _Height(root->_left);int rightHeight = _Height(root->_right);// 不平衡if (abs(leftHeight - rightHeight) >= 2){cout << root->_kv.first << endl;return false;}// 順便檢查一下平衡因子是否正確if (rightHeight - leftHeight != root->_bf){cout << root->_kv.first << endl;return false;}return _IsBalance(root->_left)&& _IsBalance(root->_right);}void _InOder(Node* _root){if (_root == nullptr){return;}InOder(_root->_left);cout << _root->_kv.first << " " << _root->_kv.second << endl;InOder(_root->_right);}private:Node* _root = nullptr;};void AVLTest1()
{AVLTree<int, int> at;
}

在這里插入圖片描述

以上就是本篇文章的所有內(nèi)容,在此感謝大家的觀看!這里是高階數(shù)據(jù)結(jié)構(gòu)筆記,希望對(duì)你在學(xué)習(xí)高階數(shù)據(jù)結(jié)構(gòu)旅途中有所幫助!

http://www.risenshineclean.com/news/57276.html

相關(guān)文章:

  • 膠州國(guó)際網(wǎng)站建設(shè)效果賺錢平臺(tái)
  • 做pc端網(wǎng)站教程百度非企渠道開戶
  • 織夢(mèng)網(wǎng)站英文版怎么做外貿(mào)建站教程
  • 青島網(wǎng)站建設(shè)哪家權(quán)威寧波網(wǎng)站優(yōu)化公司價(jià)格
  • 發(fā)布消息做任務(wù)的網(wǎng)站網(wǎng)絡(luò)推廣培訓(xùn)課程內(nèi)容
  • 如何引用網(wǎng)站圖片東莞網(wǎng)站設(shè)計(jì)公司排名
  • 池州市住房和城鄉(xiāng)建設(shè)委員會(huì)網(wǎng)站模板建站的網(wǎng)站
  • 寧波網(wǎng)站設(shè)計(jì)建站服務(wù)公司搜索引擎優(yōu)化的作用是什么
  • 網(wǎng)站優(yōu)怎么做百度一下百度網(wǎng)頁(yè)版
  • 做網(wǎng)站二維碼網(wǎng)絡(luò)推廣怎么學(xué)
  • 免費(fèi)搭建業(yè)務(wù)網(wǎng)站阿里云云服務(wù)平臺(tái)
  • 服務(wù)器租用網(wǎng)站模板寧波seo網(wǎng)絡(luò)推廣軟件系統(tǒng)
  • php裝飾公司網(wǎng)站源碼云南seo網(wǎng)站關(guān)鍵詞優(yōu)化軟件
  • 哪個(gè)網(wǎng)站做黑色星期五訂酒店活動(dòng)如何做網(wǎng)站設(shè)計(jì)
  • 咖啡網(wǎng)站設(shè)計(jì)模板有什么好的網(wǎng)站嗎
  • 常州市城鄉(xiāng)建設(shè)學(xué)院網(wǎng)站如何在百度推廣自己的產(chǎn)品
  • 有沒(méi)有專門做牛仔的網(wǎng)站谷歌引擎搜索入口
  • 政府網(wǎng)站建設(shè)運(yùn)維情況自查沈陽(yáng)seo關(guān)鍵詞排名優(yōu)化軟件
  • 建設(shè)醫(yī)療網(wǎng)站怎樣注冊(cè)一個(gè)自己的平臺(tái)
  • 臨沂網(wǎng)站建設(shè)設(shè)計(jì)公司小紅書廣告投放平臺(tái)
  • 做早餐燒菜有什么網(wǎng)站seo綜合查詢是什么
  • 內(nèi)網(wǎng)網(wǎng)站建設(shè)方案廣告視頻
  • 杭州做網(wǎng)站需要多少錢站長(zhǎng)統(tǒng)計(jì)網(wǎng)站統(tǒng)計(jì)
  • 艾辰做網(wǎng)站黑帽seo技巧
  • 有沒(méi)有專業(yè)收費(fèi)做網(wǎng)站優(yōu)化的數(shù)字化營(yíng)銷
  • 塘下網(wǎng)站建設(shè)深圳網(wǎng)絡(luò)推廣公司排名
  • 凡科網(wǎng)做的網(wǎng)站保存后就上傳了嗎深圳網(wǎng)絡(luò)推廣渠道
  • 網(wǎng)站制作哪家實(shí)惠seo權(quán)重優(yōu)化軟件
  • 深圳網(wǎng)站維護(hù)優(yōu)化百度識(shí)別圖片找圖
  • 單位加強(qiáng)網(wǎng)站建設(shè)網(wǎng)絡(luò)推廣自學(xué)