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

當前位置: 首頁 > news >正文

做網(wǎng)站即墨鄭州競價托管公司哪家好

做網(wǎng)站即墨,鄭州競價托管公司哪家好,做h5網(wǎng)站要多少錢,discuz0.前言 前面我們已經(jīng)學(xué)習(xí)過二叉搜索樹了,但如果我們是用二叉搜索樹來封裝map和set等關(guān)聯(lián)式容器是有缺陷的,很可能會退化為單分支的情況,那樣效率就極低了,那么有沒有方法來彌補二叉搜索樹的缺陷呢? 那么AVL樹就出現(xiàn)了&…

0.前言

前面我們已經(jīng)學(xué)習(xí)過二叉搜索樹了,但如果我們是用二叉搜索樹來封裝map和set等關(guān)聯(lián)式容器是有缺陷的,很可能會退化為單分支的情況,那樣效率就極低了,那么有沒有方法來彌補二叉搜索樹的缺陷呢?

那么AVL樹就出現(xiàn)了,通過AVL樹的右單旋、左單旋、左右單旋,右左單旋等操作來防止二叉搜索樹退化為單分支的情況出現(xiàn)。

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

1.AVL樹的概念

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

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

我們這里使用的平衡因子是右子樹高度 - 左子樹高度。?

?

2.AVL樹節(jié)點的定義

代碼如下:

template<class K, class V>
struct AVLTreeNode
{AVLTreeNode<K, V>* _left;	//該節(jié)點的左孩子AVLTreeNode<K, V>* _right;	//該節(jié)點的右孩子AVLTreeNode<K, V>* _parent;	//該節(jié)點的雙親pair<K, V>  _kv;	//該節(jié)點的key和valueint _bf; //balance factor 平衡因子AVLTreeNode(const pair<K, V>& kv)	//該節(jié)點初始化:_left(nullptr)  , _right(nullptr), _parent(nullptr), _kv(kv)  , _bf(0){}
};

3.AVL樹的插入

AVL樹就是在二叉搜索樹的基礎(chǔ)上引入了平衡因子,因此AVL樹也可以看成是二叉搜索樹。那么
AVL樹的插入過程可以分為兩步:

  1. 按照二叉搜索樹的方式插入新節(jié)點
  2. 調(diào)整節(jié)點的平衡因子
    ?

插入思路

?1.按照搜索樹規(guī)則插入

2.更新插入節(jié)點的祖先節(jié)點的平衡因子

? ? ? ? a.插入父親的右邊,父親的平衡因子--

? ? ? ? b.插入父親的左邊,父親的平衡因子++

? ? ? ? c.父親平衡因子 == 0, 父親所在子樹高度不變,不再繼續(xù)往上更新。插入結(jié)束

? ? ? ? d.父親平衡因子 == 1 or -1, 父親所在子樹高度變了,繼續(xù)往上更新。

? ? ? ? e.父親平衡因子 == 2 or -2, 父親所在子樹已經(jīng)不平衡了,需要旋轉(zhuǎn)處理。

更新中不可能出現(xiàn)其他值,插入之前樹是AVL樹,平衡因子要么是1 -1 0, ++ --

最多就是c/d/e三種情況。

?代碼如下

	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;}else{parent->_left = cur;}cur->_parent = parent;//更新平衡因子while (parent){if (cur == parent->_left){parent->_bf--;}else{parent->_bf++;}if (parent->_bf == 0){//更新結(jié)束break;}else if (parent->_bf == -1 || parent->_bf == 1){//繼續(xù)往上更新cur = parent;parent = parent->_parent;}else if (parent->_bf == -2 || parent->_bf == 2){//當前子樹出現(xiàn)了問題,需要旋轉(zhuǎn)平衡一下if (parent->_bf == -2 && cur->_bf == -1){//右單旋RotateR(parent);}else if (parent->_bf == 2 && cur->_bf == 1){//左單旋RotateL(parent);}else if (parent->_bf == -2 && cur->_bf == 1){//左右雙旋RotateLR(parent);}else if (parent->_bf == 2 && cur->_bf == -1){//右左雙旋//RotateRL(parent);}break;}else{//理論上不會出現(xiàn)這種情況,但仍要判斷,大佬都不能保證自己的代碼沒有bugassert(false);}}return true;}

4.AVL樹的旋轉(zhuǎn)

4.1 右單旋

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

圖形解析:

?實現(xiàn)代碼如下:

	void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)	//subLR有可能為空,不為空時才能調(diào)整subLR的父節(jié)點subLR->_parent = parent;subL->_right = parent;//parent不一定就是根節(jié)點,也可能是子樹,所以要設(shè)置一個ppNode來標記parent的父節(jié)點Node* ppNode = parent->_parent;parent->_parent = subL;if (parent == _root){_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;}

4.2 左單旋

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

圖形解析:

?代碼如下:

	void RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)	//subRL有可能為空,不為空時才能調(diào)整subRL的父節(jié)點subRL->_parent = parent;subR->_left = parent;//parent不一定就是根節(jié)點,也可能是子樹,所以要設(shè)置一個ppNode來標記parent的父節(jié)點Node* ppNode = parent->_parent;parent->_parent = subR;if (parent == _root){_root = subR;_root->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subR;}else{ppNode->_right = subR;}subR->_parent = ppNode;}subR->_bf = parent->_bf = 0;}

4.3 左右雙旋

插入新節(jié)點要插入較高左子樹的右側(cè)(左右)-》左右雙旋

圖形解析:

對于插入的位置根據(jù)h的高度和插入的位置時的平衡因子出現(xiàn)的最終的結(jié)果可分為三種情況:

1.h == 0

? ? ? ? 60自己就是新增節(jié)點。bf == 0

此時的平衡因子為,30 60 90節(jié)點都為0。

2.h > 0

? ? ? ? a.新增節(jié)點插入的是60的左子樹中 bf == -1

此時的平衡因子為,30節(jié)點為0,90為0,60為1

? ? ? ? b.新增節(jié)點插入的是60的右子樹中bf?== 1

此時的平衡因子為,30節(jié)點為-1,90為0,60為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){subL->_bf = 0;subLR->_bf = 0;parent->_bf = 0;}else if (bf == -1){subL->_bf = 0;subLR->_bf = 0;parent->_bf = 1;}else if (bf == 1){subL->_bf = -1;subLR->_bf = 0;parent->_bf = 0;}else{//理論上不會出現(xiàn)的情況assert(false);}}

4.4 右左雙旋

插入新節(jié)點要插入較高右子樹的左側(cè)(右左)-》右左雙旋

與左右雙旋類似

代碼如下:

	void RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(parent->_right);RotateL(parent);if (bf == 0){parent->_bf = 0;subRL->_bf = 0;subR->_bf = 0;}else if (bf == -1){parent->_bf = 0;subRL->_bf = 0;subR->_bf = 1;}else if (bf == 1){parent->_bf = -1;subRL->_bf = 0;subR->_bf = 0;}else{//理論上不會出現(xiàn)的情況assert(false);}}


總結(jié)
假如以pParent為根的子樹不平衡,即pParent的平衡因子為2或者-2,分以下情況考慮
1. pParent的平衡因子為2,說明pParent的右子樹高,設(shè)pParent的右子樹的根為pSubR
當pSubR的平衡因子為1時,執(zhí)行左單旋
當pSubR的平衡因子為-1時,執(zhí)行右左雙旋
2. pParent的平衡因子為-2,說明pParent的左子樹高,設(shè)pParent的左子樹的根為pSubL
當pSubL的平衡因子為-1是,執(zhí)行右單旋
當pSubL的平衡因子為1時,執(zhí)行左右雙旋
旋轉(zhuǎn)完成后,原pParent為根的子樹個高度降低,已經(jīng)平衡,不需要再向上更新。

?

5.AVL樹的驗證

5.1 驗證其是否為二叉搜索樹

給一個序列進行一次中序遍歷,看是否有序,有序即為二叉搜索樹。

void TestAVLTree1()
{int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };AVLTree<int, int> t1;for (auto e : a){t1.Insert({ e,e });}t1.InOrder();
}

5.2 驗證其是否為平衡樹

	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);}

6.AVL樹的刪除(了解)

因為AVL樹也是二叉搜索樹,可按照二叉搜索樹的方式將節(jié)點刪除,然后再更新平衡因子,只不錯與刪除不同的時,刪除節(jié)點后的平衡因子更新,最差情況下一直要調(diào)整到根節(jié)點的位置。

7.AVL樹的性能

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

?8.AVL樹的整體模擬代碼實現(xiàn)

#pragma once
#include<iostream>
using namespace std;
#include<assert.h>template<class K, class V>
struct AVLTreeNode
{AVLTreeNode<K, V>* _left;	//該節(jié)點的左孩子AVLTreeNode<K, V>* _right;	//該節(jié)點的右孩子AVLTreeNode<K, V>* _parent;	//該節(jié)點的雙親pair<K, V>  _kv;	//該節(jié)點的key和valueint _bf; //balance factor 平衡因子AVLTreeNode(const pair<K, V>& kv)	//該節(jié)點初始化:_left(nullptr)  , _right(nullptr), _parent(nullptr), _kv(kv)  , _bf(0){}
};template<class K, class V>
class 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;}else{parent->_left = cur;}cur->_parent = parent;//更新平衡因子while (parent){if (cur == parent->_left){parent->_bf--;}else{parent->_bf++;}if (parent->_bf == 0){//更新結(jié)束break;}else if (parent->_bf == -1 || parent->_bf == 1){//繼續(xù)往上更新cur = parent;parent = parent->_parent;}else if (parent->_bf == -2 || parent->_bf == 2){//當前子樹出現(xiàn)了問題,需要旋轉(zhuǎn)平衡一下if (parent->_bf == -2 && cur->_bf == -1){//右單旋RotateR(parent);}else if (parent->_bf == 2 && cur->_bf == 1){//左單旋RotateL(parent);}else if (parent->_bf == -2 && cur->_bf == 1){//左右雙旋RotateLR(parent);}else if (parent->_bf == 2 && cur->_bf == -1){//右左雙旋RotateRL(parent);}break;}else{//理論上不會出現(xiàn)這種情況,但仍要判斷,大佬都不能保證自己的代碼沒有bugassert(false);}}return true;}void RotateR(Node* parent){Node* subL = parent->_left;Node* subLR = subL->_right;parent->_left = subLR;if (subLR)	//subLR有可能為空,不為空時才能調(diào)整subLR的父節(jié)點subLR->_parent = parent;subL->_right = parent;//parent不一定就是根節(jié)點,也可能是子樹,所以要設(shè)置一個ppNode來標記parent的父節(jié)點Node* ppNode = parent->_parent;parent->_parent = subL;if (parent == _root){_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 RotateL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;parent->_right = subRL;if (subRL)	//subRL有可能為空,不為空時才能調(diào)整subRL的父節(jié)點subRL->_parent = parent;subR->_left = parent;//parent不一定就是根節(jié)點,也可能是子樹,所以要設(shè)置一個ppNode來標記parent的父節(jié)點Node* ppNode = parent->_parent;parent->_parent = subR;if (parent == _root){_root = subR;_root->_parent = nullptr;}else{if (ppNode->_left == parent){ppNode->_left = subR;}else{ppNode->_right = subR;}subR->_parent = ppNode;}subR->_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 == 0){subL->_bf = 0;subLR->_bf = 0;parent->_bf = 0;}else if (bf == -1){subL->_bf = 0;subLR->_bf = 0;parent->_bf = 1;}else if (bf == 1){subL->_bf = -1;subLR->_bf = 0;parent->_bf = 0;}else{//理論上不會出現(xiàn)的情況assert(false);}}void RotateRL(Node* parent){Node* subR = parent->_right;Node* subRL = subR->_left;int bf = subRL->_bf;RotateR(parent->_right);RotateL(parent);if (bf == 0){parent->_bf = 0;subRL->_bf = 0;subR->_bf = 0;}else if (bf == -1){parent->_bf = 0;subRL->_bf = 0;subR->_bf = 1;}else if (bf == 1){parent->_bf = -1;subRL->_bf = 0;subR->_bf = 0;}else{//理論上不會出現(xiàn)的情況assert(false);}}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{return cur;}}return nullptr;}void InOrder(){_InOrder(_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 _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_kv.first << ":" << root->_kv.second << endl;_InOrder(root->_right);}Node* _root = nullptr;
};void TestAVLTree1()
{int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };AVLTree<int, int> t1;for (auto e : a){t1.Insert({ e,e });}t1.InOrder();
}
void TestAVLTree2()
{int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };AVLTree<int, int> t1;for (auto e : a){t1.Insert({ e,e });}t1.InOrder();cout << t1.IsBalance() << endl;
}

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

相關(guān)文章:

  • 賀卡制作優(yōu)化資訊
  • 榆次建設(shè)局網(wǎng)站普通話手抄報簡單又漂亮
  • 個人網(wǎng)站建站指南他達那非片能延時多久
  • php做網(wǎng)站的好處寧波seo外包推廣渠道
  • 購物網(wǎng)站圖片的放大怎么做的seo網(wǎng)絡(luò)推廣教程
  • html5網(wǎng)站下載建站模板哪個好
  • 網(wǎng)絡(luò)營銷應(yīng)該這樣做seo優(yōu)化交流
  • 保定企業(yè)網(wǎng)站制作電商數(shù)據(jù)統(tǒng)計網(wǎng)站
  • 目前流行的網(wǎng)站開發(fā)技術(shù)浙江專業(yè)網(wǎng)站seo
  • 高端網(wǎng)站定制策劃長沙官網(wǎng)seo技巧
  • 可以做書的網(wǎng)站全國疫情最新公布
  • 站長平臺有哪些交換友情鏈接的方法
  • 談?wù)勀銓W(wǎng)站建設(shè)有什么樣好的建設(shè)意見做一個簡單的網(wǎng)站需要多少錢
  • 一般做網(wǎng)站需要的js有哪些網(wǎng)絡(luò)營銷的方法
  • web前端開發(fā)視頻教學(xué)seo排名是什么
  • 真正能約拍的app做好的網(wǎng)站怎么優(yōu)化
  • p2p做網(wǎng)站貴州二級站seo整站優(yōu)化排名
  • 機關(guān)事業(yè)單位網(wǎng)站備案谷歌瀏覽器下載
  • ibm網(wǎng)站導(dǎo)航特效代碼信息流廣告投放平臺
  • 高端做網(wǎng)站哪家好百度一下官網(wǎng)首頁登錄
  • 臺州網(wǎng)站建設(shè)優(yōu)化深圳seo推廣
  • 金華專業(yè)做網(wǎng)站建站推廣
  • 互聯(lián)網(wǎng)金融網(wǎng)站設(shè)計百度收錄查詢工具
  • 模型下載網(wǎng)站開發(fā)流程廣州網(wǎng)頁制作
  • 網(wǎng)站建設(shè)月總結(jié)怎么做百度關(guān)鍵詞排名
  • 網(wǎng)站首頁的動態(tài)視頻怎么做的公司seo排名優(yōu)化
  • 給網(wǎng)站做插畫分辨率seo也成搜索引擎優(yōu)化
  • 北京網(wǎng)站建設(shè)天下公司網(wǎng)絡(luò)營銷品牌
  • 公司怎么建網(wǎng)站做推廣日本疫情最新數(shù)據(jù)
  • 棗莊三合一網(wǎng)站開發(fā)百度安裝應(yīng)用