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

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

石家莊網(wǎng)站建設(shè).神鹿網(wǎng)絡(luò)網(wǎng)站關(guān)鍵詞排名優(yōu)化工具

石家莊網(wǎng)站建設(shè).神鹿網(wǎng)絡(luò),網(wǎng)站關(guān)鍵詞排名優(yōu)化工具,做二手手機(jī)交易網(wǎng)站,wordpress導(dǎo)入tumblr文章目錄一、AVL樹的概念二、AVL樹節(jié)點的定義三、AVL樹的插入四、AVL樹的旋轉(zhuǎn)1.左單旋2.右單旋3.左右雙旋4.右左雙旋五、進(jìn)行驗證六、AVLTree的性能個人簡介📝 🏆2022年度博客之星Top18;🏆2022社區(qū)之星Top2;的🥇C/C領(lǐng)域優(yōu)質(zhì)創(chuàng)作者…

文章目錄

    • 一、AVL樹的概念
    • 二、AVL樹節(jié)點的定義
    • 三、AVL樹的插入
    • 四、AVL樹的旋轉(zhuǎn)
      • 1.左單旋
      • 2.右單旋
      • 3.左右雙旋
      • 4.右左雙旋
    • 五、進(jìn)行驗證
    • 六、AVLTree的性能

個人簡介📝

🏆2022年度博客之星Top18;🏆2022社區(qū)之星Top2;的🥇C/C++領(lǐng)域優(yōu)質(zhì)創(chuàng)作者;

🥇阿里云專家博主;🥇華為云云享專家;🥇騰訊云年度進(jìn)取作者;🥇掘金成長之星;

一、AVL樹的概念

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

因此,兩位俄羅斯的數(shù)學(xué)家G.M.Adelson-Velskii和E.M.Landis在1962年發(fā)明了一種解決上述問題的方法:當(dāng)向二叉搜索樹中插入新結(jié)點后,如果能保證每個結(jié)點的左右子樹高度之差的絕對值不超過1(需要對樹中的結(jié)點進(jìn)行調(diào)整),即可降低樹的高度,從而減少平均搜索長度
一棵AVL樹或者是空樹,或者是具有以下性質(zhì)的二叉搜索樹

它的左右子樹都是AVL樹
左右子樹高度之差(簡稱平衡因子)的絕對值不超過1(-1/0/1)

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

image-20230211114707078

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


二、AVL樹節(jié)點的定義

節(jié)點結(jié)構(gòu):三叉鏈結(jié)構(gòu)(左、右、父),以及平衡因子bf+構(gòu)造函數(shù)(左右為空,平衡因子初始化為0)

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

三、AVL樹的插入

AVL樹在二叉搜索樹的基礎(chǔ)上引入了平衡因子,因此AVL樹也可以看成是二叉搜索樹。步驟過程

找到插入的位置:根據(jù)二叉搜索樹的做法

進(jìn)行插入:判斷插入的位置是parent的左還是右

更新平衡因子:如果不平衡的話,就要進(jìn)行旋轉(zhuǎn)

找到插入位置(比較節(jié)點大小即可):

  • 插入的節(jié)點key值 > 當(dāng)前位置的key值,往右子樹走
  • 插入的節(jié)點key值 < 當(dāng)前位置的key值,往左子樹走
  • 插入的節(jié)點key值等于當(dāng)前位置的key值,不能插入,返回false

插入之后,與二叉搜索樹不同的是:我們還需要去進(jìn)行平衡因子的更新,調(diào)平衡:

如果新增加的在右,平衡因子加加

如果新增加的在左,平衡因子減減

更新一個結(jié)點之后我們需要去進(jìn)行判斷,子樹的高度是否發(fā)生了變化:

1.如果parent的平衡因子是0:說明之前parent的平衡因子是1或-1,說明之前parent一邊高、一邊低;這次插入之后填入矮的那邊,parent所在的子樹高度不變,不需要繼續(xù)往上更新

2.如果parent的平衡因子是1或者-1:說明之前parent的平衡因子是0,兩邊一樣高,插入之后一邊更高,parent所在的子樹高度發(fā)生變化,繼續(xù)往上更新

3.平衡因子是2或-2,說明之前parent的平衡因子是1或-1,現(xiàn)在插入嚴(yán)重不平衡,違反規(guī)則,需要進(jìn)行旋轉(zhuǎn)處理

最壞的情況下:需要一直更新到根root:

image-20230211160543324

我們更新平衡因子時第一個更新的就是parent,如果parent->_bf1或parent->_bf-1需要繼續(xù)往上進(jìn)行平衡因子的更新,向上迭代,直到parent為空的情況:

else if (parent->_bf == 1 || parent->_bf == -1)
{cur = parent;parent = parent->_parent;
}

當(dāng)parent->_bf = 2或parent->_bf==-2時,我們就需要進(jìn)行旋轉(zhuǎn)了

🔴如果parent的平衡因子是2,cur的平衡因子是1時,說明右邊的右邊比較高,我們需要進(jìn)行左單旋

🔴如果parent的平衡因子是-2,cur的平衡因子是-1時,說明左邊的左邊比較高,我們需要進(jìn)行右單旋

🔴如果parent的平衡因子是-2,cur的平衡因子是1時,我們需要進(jìn)行左右雙旋

🔴如果parent的平衡因子是2,cur的平衡因子是-1時,我們需要進(jìn)行右左雙旋

bool Insert(const pair<K, V>& kv){if (_root == nullptr){_root = new Node(kv);return true;}Node* parent = nullptr;Node* cur = _root;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{return false;}}cur = new Node(kv);if (parent->_kv.first < kv.first){parent->_right = cur;cur->_parent = parent;}else{parent->_left = cur;cur->_parent = parent;}//更新平衡因子while (parent){if (cur == parent->_left){parent->_bf--;}else{parent->_bf++;}if (parent->_bf == 0){break;}else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = parent->_parent;}else if(parent->_bf==2||parent->_bf==-2){//左旋轉(zhuǎn)if (parent->_bf == 2 && cur->_bf == 1){RotateL(parent);}//右旋else if (parent->_bf == -2 && cur->_bf == -1){RotateR(parent);}//左右雙旋else if (parent-> _bf == -2&&cur->_bf==1){RotateLR(parent);}//右左雙旋else if (parent->_bf ==2&&cur->_bf ==-1){RotateRL(parent);}else{assert(false);}break;}else{assert(false);}}return true;}

四、AVL樹的旋轉(zhuǎn)

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

旋轉(zhuǎn)規(guī)則:

1.讓這顆子樹左右高度差不超過1

2.旋轉(zhuǎn)過程中繼續(xù)保持它是搜索樹

3.更新調(diào)整孩子節(jié)點的平衡因子

4.讓這顆子樹的高度根插入前保持一致

1.左單旋

新節(jié)點插入較高右子樹的右側(cè)—右右:左單旋

抽象圖:

image-20230211213046519

a/b/c是高度為h的AVL子樹,代表多數(shù)情況:h>=0,其中h可以等于0、1、2…,不過都可以抽象成h,處理情況都一樣:此時parent等于2,subR等于1。

具體左旋的步驟:

subRL成為parent的右子樹:注意subL和parent的關(guān)系,調(diào)整parent的右以及subRL的父(subRL可能為空)

parent成為subR的左子樹:調(diào)整parent的父與subR的左

subR成為相對的根節(jié)點:調(diào)整subR與ppNode:注意parent是不是整棵樹的root,如果是,則讓subR為_root,同時讓_root->_parent置為空

更新平衡因子

左旋調(diào)整:subR的左子樹值(subRL)本身就比parent的值要大,所以可以作為parent的右子樹;而parent及其左子樹當(dāng)中結(jié)點的值本身就比subR的值小,所以可以作為subR的左子樹。

**更新平衡因子bf:**subR與parent的bf都更新為0

image-20230211223628460

代碼實現(xiàn)左旋轉(zhuǎn):

//左單旋void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;Node* ppNode = parent->_parent;subR->_left = parent;parent->_parent = subR;if (ppNode == nullptr){_root = subR;_root->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subR;}else{ppNode->_right = subR;}subR->_parent = ppNode;}parent->_bf = subR->_bf = 0;}

2.右單旋

新節(jié)點插入較高左子樹的左側(cè)—左左:右單旋

有了前面左旋的基礎(chǔ),我們在來看右旋就沒有那么費勁了:

image-20230211233536643

a/b/c是高度為h的AVL樹,右旋旋轉(zhuǎn)動作:b變成60的左邊,60變成30的右邊,30變成子樹的根。
30比60小,b值是處于30和60之間,此時作為60的左邊是沒有問題的。

有了這個圖,在結(jié)合前面左單旋的基礎(chǔ),我們就能很快實現(xiàn)我們的右單旋代碼:

//右單旋
void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;Node* ppNode = parent->_parent;parent->_parent = subL;subL->_right = parent;//if(_root==parent)if (ppNode == nullptr){_root = subL;_root->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subL;}else{ppNode->_right = subL;}subL->_parent = ppNode;}subL->_bf = parent->_bf = 0;}

3.左右雙旋

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

image-20230212153433568

a/d是高度為h的AVL樹,b/c是高度為h-1的AVL樹。

以30為軸點進(jìn)行左單旋:b變成30的右邊,30變成60的左邊,60變成子樹根

image-20230212154430704

以90為軸點進(jìn)行右單旋:c變成90的左邊,90變成60的右邊,60變成子樹的根

image-20230212160647342

左右雙旋:以subL為軸點左旋,以parent為軸點進(jìn)行右旋,在進(jìn)行平衡因子的更新(最大的問題)

我們從總體的角度來看,左右雙旋的結(jié)果就是:就是把subLR的左子樹和右子樹,分別作為subL和parent的右子樹和左子樹,同時subL和parent分別作為subLR的左右子樹,最后讓subLR作為整個子樹的根

subLR的左子樹作為subL的右子樹:因為subLR的左子樹結(jié)點比subL的大

subLR的右子樹作為parent的左子樹:因為subLR的右子樹結(jié)點比parent的小

平衡因子的更新:重新判斷(識別插入節(jié)點是在b還是在c)根據(jù)subLR平衡因子的初始情況進(jìn)行分類:

  • 如果subLR初始平衡因子是-1時,左右雙旋后parent、subL、subLR的平衡因子分別更新為1、0、0(插入在b)

image-20230212165105682

  • 如果subLR的初始平衡因子是1時,左右雙旋后parent、subL、subLR的平衡因子分別更新為0、-1、0(插入在c)

image-20230212170233716

  • 如果subLR初始平衡因子是0時,左右雙旋后parent、subL、subLR的平衡因子分別更新為0、0、0(subLR自己新增)

image-20230212171341596

代碼實現(xiàn)

//左右雙旋void RotateLR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;int bf = subLR ->_bf;RotateL(parent->_left);RotateR(parent);//更新平衡因子if (bf == -1)//b插入,subLR左子樹新增{subL->_bf = 0;parent->_bf = 1;subLR->_bf = 0;}else if (bf == 1)//c插入,subLR右子樹新增{parent->_bf = 0;subL->_bf = -1;subLR->_bf = 0;}else if (bf == 0)//subLR自己新增加{parent->_bf = 0;subL->_bf = 0;subLR->_bf = 0;}else{assert(false);}}

4.右左雙旋

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

插入

image-20230212213033620

subR為軸點進(jìn)行右單旋:

image-20230212214355843

parent為軸進(jìn)行左單旋:

image-20230212215237967

既右左雙旋:

image-20230212215643450

右左雙旋后,根據(jù)subRL 初始平衡因子的不同分為三種情況分別對應(yīng)subRL = 0、1、-1情況,與左右雙旋情況類似。

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

五、進(jìn)行驗證

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

  • 驗證其為二叉搜索樹
    如果中序遍歷可得到一個有序的序列,就說明為二叉搜索樹
	void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_InOrder(root->_right);}
  • 驗證其為平衡樹
    每個節(jié)點子樹高度差的絕對值不超過1(注意節(jié)點中如果沒有平衡因子)節(jié)點的平衡因子是否計算正確

    如果是空樹,是AVL樹;高度差不大于2,并且遞歸左右子樹的高度差都不大于2,也是AVL樹;判斷平衡因子和該點的高度差是否相等

//求高度
int Height(Node* root){if (root == nullptr)return 0;int lh = Height(root->_left);int rh = Height(root->_right);return lh > rh ? lh + 1 : rh + 1;}
//判斷平衡
bool IsBalance(Node* root){if (root == nullptr){return true;}int leftHeight = Height(root->_left);int rightHeight = Height(root->_right);if (rightHeight - leftHeight != root->_bf){cout << root->_kv.first << "平衡因子異常" << endl;return false;}return abs(rightHeight - leftHeight) < 2&& IsBalance(root->_left)&& IsBalance(root->_right);}

六、AVLTree的性能

AVL樹是一棵絕對平衡的二叉搜索樹,其要求每個節(jié)點的左右子樹高度差的絕對值都不超過1,這樣可以保證查詢時高效的時間復(fù)雜度即log2( N) 。但是如果要對AVL樹做一些結(jié)構(gòu)修改的操作,性能非常低下,比如:插入時要維護(hù)其絕對平衡,旋轉(zhuǎn)的次數(shù)比較多,更差的是在刪除時,有可能一直要讓旋轉(zhuǎn)持續(xù)到根的位置。
因此:如果需要一種查詢高效且有序的數(shù)據(jù)結(jié)構(gòu),而且數(shù)據(jù)的個數(shù)為靜態(tài)的(即不會改變),可以考慮AVL樹,但一個結(jié)構(gòu)經(jīng)常修改,就不太適合.


送上源碼:

#pragma once
#include <iostream>
#include <assert.h>
#include <time.h>
using namespace std;
template<class K,class V>
struct AVLTreeNode
{pair<K, V> _kv;AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;int _bf;//balance factorAVLTreeNode(const pair<K,V>&kv):_kv(kv),_left(nullptr),_right(nullptr),_parent(nullptr),_bf(0){}
};template <class K,class V>
struct AVLTree
{typedef AVLTreeNode<K, V> Node;
public:bool Insert(const pair<K, V>& kv){if (_root == nullptr){_root = new Node(kv);return true;}Node* parent = nullptr;Node* cur = _root;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{return false;}}cur = new Node(kv);if (parent->_kv.first < kv.first){parent->_right = cur;cur->_parent = parent;}else{parent->_left = cur;cur->_parent = parent;}//更新平衡因子while (parent){if (cur == parent->_left){parent->_bf--;}else{parent->_bf++;}if (parent->_bf == 0){break;}else if (parent->_bf == 1 || parent->_bf == -1){cur = parent;parent = parent->_parent;}else if(parent->_bf==2||parent->_bf==-2){//左旋轉(zhuǎn)if (parent->_bf == 2 && cur->_bf == 1){RotateL(parent);}//右旋else if (parent->_bf == -2 && cur->_bf == -1){RotateR(parent);}//左右雙旋else if (parent-> _bf == -2&&cur->_bf==1){RotateLR(parent);}//右左雙旋else if (parent->_bf ==2&&cur->_bf ==-1){RotateRL(parent);}else{assert(false);}break;}else{assert(false);}}return true;}//左單旋void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)subRL->_parent = parent;Node* ppNode = parent->_parent;subR->_left = parent;parent->_parent = subR;if (ppNode == nullptr){_root = subR;_root->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subR;}else{ppNode->_right = subR;}subR->_parent = ppNode;}parent->_bf = subR->_bf = 0;}void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)subLR->_parent = parent;Node* ppNode = parent->_parent;parent->_parent = subL;subL->_right = parent;//if(_root==parent)if (ppNode == nullptr){_root = subL;_root->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subL;}else{ppNode->_right = subL;}subL->_parent = ppNode;}subL->_bf = parent->_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 == -1)//b插入,subLR左子樹新增{subL->_bf = 0;parent->_bf = 1;subLR->_bf = 0;}else if (bf == 1)//c插入,subLR右子樹新增{parent->_bf = 0;subL->_bf = -1;subLR->_bf = 0;}else if (bf == 0)//subLR自己新增加{parent->_bf = 0;subL->_bf = 0;subLR->_bf = 0;}else{assert(false);}}//右左雙旋void RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(subR);RotateL(parent);if (bf == 1){subR->_bf = 0;subRL->_bf = 0;parent->_bf = -1;}else if (bf == -1){subR->_bf = 1;subRL->_bf = 0;parent->_bf = 0;}else if (bf == 0){subR->_bf = 0;subRL->_bf = 0;parent->_bf = 0;}else{assert(false);}}void InOrder(){_InOrder(_root);}void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_InOrder(root->_right);}int Height(Node* root){if (root == nullptr)return 0;int lh = Height(root->_left);int rh = Height(root->_right);return lh > rh ? lh + 1 : rh + 1;}bool IsBalance(){return IsBalance(_root);}bool IsBalance(Node* root){if (root == nullptr){return true;}int leftHeight = Height(root->_left);int rightHeight = Height(root->_right);if (rightHeight - leftHeight != root->_bf){cout << root->_kv.first << "平衡因子異常" << endl;return false;}return abs(rightHeight - leftHeight) < 2&& IsBalance(root->_left)&& IsBalance(root->_right);}
private:Node* _root = nullptr;
};//測試
void TestAVLTree()
{//int a[] = { 8,3,1,10,6,4,7,14,13 };//int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };int a[] = { 4,2,6,1,3,5,15,7,16,14 };AVLTree<int, int> t;for (auto e : a){t.Insert(make_pair(e,e));}t.InOrder();cout << t.IsBalance() << endl;
}void TestAVLTree2()
{srand(time(0));const size_t N = 100000;AVLTree<int, int> t;for (size_t i = 0; i < N; i++){size_t x = rand();t.Insert(make_pair(x, x));}//t.InOrder();cout << t.IsBalance() << endl;
}

本篇結(jié)束…

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

相關(guān)文章:

  • 在線看私人不收費不登錄網(wǎng)絡(luò)優(yōu)化工程師簡歷
  • 一個好的網(wǎng)站需要具備什么深圳網(wǎng)站維護(hù)
  • 有關(guān)中國文明網(wǎng)聯(lián)盟網(wǎng)站建設(shè)活動方案seo排名優(yōu)化軟件有用嗎
  • wp rocket wordpress重慶seo是什么
  • 剛做的網(wǎng)站怎么知道有沒有潛在的今日國際軍事新聞頭條
  • 大興快速網(wǎng)站建設(shè)公司百度在線入口
  • 怎么做網(wǎng)站平臺產(chǎn)品營銷
  • 馬鞍山 做網(wǎng)站aso優(yōu)化的主要內(nèi)容
  • 在越南做網(wǎng)站需要什么企業(yè)推廣公司
  • 咸陽網(wǎng)站建設(shè)學(xué)校代發(fā)軟文
  • php創(chuàng)建網(wǎng)頁seo網(wǎng)站快速排名
  • 安徽建站系統(tǒng)搜索排名優(yōu)化軟件
  • 免費的行情網(wǎng)站app網(wǎng)頁推薦企業(yè)網(wǎng)站的域名是該企業(yè)的
  • 個人網(wǎng)站做什么類型的泰州網(wǎng)站優(yōu)化公司
  • 北京市官網(wǎng)谷歌網(wǎng)站優(yōu)化
  • 互聯(lián)網(wǎng)運營模式有哪幾種同仁seo排名優(yōu)化培訓(xùn)
  • b北京網(wǎng)站建設(shè)推廣賺錢軟件排行
  • 地方新聞網(wǎng)站好壞網(wǎng)絡(luò)宣傳方式
  • 石柱網(wǎng)站開發(fā)品牌推廣活動有哪些
  • 貴州城鄉(xiāng)建設(shè)官方網(wǎng)站廣州百度seo代理
  • 做全景圖有哪些網(wǎng)站西安網(wǎng)站建設(shè)維護(hù)
  • ps做網(wǎng)站首頁怎么個人網(wǎng)上賣貨的平臺
  • h5制作小程序有哪些優(yōu)化方案模板
  • 墾利住房和城鄉(xiāng)建設(shè)局網(wǎng)站圖片搜索圖片識別
  • 用手機(jī)怎么看自己做的網(wǎng)站網(wǎng)頁設(shè)計大作業(yè)
  • 微商城開發(fā)發(fā)搜索引擎優(yōu)化包括哪些方面
  • 網(wǎng)站怎么做搜索功能重慶電子商務(wù)網(wǎng)站seo
  • 怎樣制作屬于自己的網(wǎng)站網(wǎng)站分享
  • 網(wǎng)站兼容性怎么調(diào)培訓(xùn)方案怎么做
  • 如何做賣菜網(wǎng)站不限次數(shù)觀看視頻的app