欧美free性护士vide0shd,老熟女,一区二区三区,久久久久夜夜夜精品国产,久久久久久综合网天天,欧美成人护士h版

首頁綜合 正文
目錄

柚子快報(bào)激活碼778899分享:算法 C++:AVL樹

柚子快報(bào)激活碼778899分享:算法 C++:AVL樹

http://yzkb.51969.com/

目錄

AVL樹概念

AVL樹的實(shí)現(xiàn)

AVL樹的節(jié)點(diǎn)

AVL樹的插入

AVL樹的平衡調(diào)整

右單旋

左單旋

左右雙旋

右左雙旋

完整的插入函數(shù)

AVL樹的查找

AVL樹的驗(yàn)證

驗(yàn)證有序

驗(yàn)證平衡

完整代碼

AVL樹概念

AVL樹是一種具有特殊性質(zhì)的二叉搜索樹,AVL樹的左右子樹也都是AVL樹,且左右子樹的高度差的絕對(duì)值不超過1,超過1就說明AVL樹失衡,需要調(diào)整。AVl樹是一顆高度平衡的二叉搜索樹,通過高度控制高度差去控制平衡。

AVL樹對(duì)比二叉搜索樹多引入了一個(gè)平衡因子的概念,每個(gè)節(jié)點(diǎn)都有一個(gè)平衡因子,任何節(jié)點(diǎn)的平衡因子等于右子樹的高度減去左子樹的高度,所以說平衡因子的取值是0、1和-1。

AVL樹整體節(jié)點(diǎn)和分布與完全二叉樹類似,高度控制在logN范圍內(nèi),那么增刪查改的效率也可以控制在O(logN),相比二叉搜索樹有了本質(zhì)提升。

以下這棵樹就是AVL樹。

? ?????????

AVL樹的實(shí)現(xiàn)

AVL樹的節(jié)點(diǎn)

由于在調(diào)整失衡的AVL樹時(shí),需要頻繁訪問父節(jié)點(diǎn),所以我們?cè)诙x節(jié)點(diǎn)時(shí)也需要引入parent指針。

template

struct AVLTreeNode

{

pair _kv;

AVLTreeNode* _left;

AVLTreeNode* _right;

AVLTreeNode* _parent;

int _bf;

AVLTreeNode(const pair& kv)

:_kv(kv)

, _left(nullptr)

,_right(nullptr)

,_parent(nullptr)

,_bf(0)

{}

};

AVL樹的插入

向AVL樹插入新節(jié)點(diǎn)的過程與二叉搜索樹的插入類似,但有區(qū)別的是,插入新節(jié)點(diǎn)后需要更新平衡因子,然后根據(jù)平衡因子的情況判斷AVL樹是否失衡,失衡就對(duì)AVL樹進(jìn)行調(diào)整。

按照平衡因子的計(jì)算公式,如果新節(jié)點(diǎn)插入到了父親節(jié)點(diǎn)的左邊,那么父親的平衡因子-1,反之,如果插入到右邊,父親的平衡因子+1。

更新后的平衡因子的情況,可以分為兩種:1.平衡因子(從1/-1)變成0。?2.平衡因子(從0)變成1/-1。

情況1就說明已經(jīng)完成平衡因子的更新了,情況2就還得繼續(xù)更新,因?yàn)楫?dāng)父親的平衡因子為1/-1時(shí),說明以父親為根節(jié)點(diǎn)的子樹高度發(fā)生了變化,這樣會(huì)影響父親的父親的平衡因子,所以需要繼續(xù)往上更新平衡因子。

template

class AVLTree

{

typedef AVLTreeNode Node;

public:

bool Insert(const pair& kv)

{

//空樹的情況特殊處理

if (_root == nullptr)

{

_root = new Node(kv);

return true;

}

//不是空樹的情況

Node* parent = nullptr;

Node* cur = _root;

//查找新節(jié)點(diǎn)的插入位置

while (cur)

{

parent = cur;

if (kv.first > cur->_kv.first)

cur = cur->_right;

else if (kv.first < cur->_kv.first)

cur = cur->_left;

else

return false;

}

cur = new Node(kv);

//將父節(jié)點(diǎn)與新節(jié)點(diǎn)鏈接

//判斷新節(jié)點(diǎn)插入到parent的左邊還是右邊

if (kv.first > parent->_kv.first) //新節(jié)點(diǎn)插入到parent的右邊

parent->_right = cur;

else

parent->_left = cur;

//更改新節(jié)點(diǎn)的父親指針

cur->_parent = parent;

//更新平衡因子

while (parent)

{

//插入節(jié)點(diǎn)后除了對(duì)父節(jié)點(diǎn)造成影響還可能對(duì)祖宗節(jié)點(diǎn)造成影響

//隨著循環(huán)進(jìn)行,cur不一定為新節(jié)點(diǎn)

//更新父節(jié)點(diǎn)的平衡因子

if (cur == parent->_left)

parent->_bf--;

else

parent->_bf++;

//檢查更新后父親的平衡因子

//_bf為0,說明樹還是AVL樹,退出循環(huán)

if (parent->_bf == 0)

break;

//_bf == 1/-1,說明需要繼續(xù)向上更新平衡因子

else if (parent->_bf == 1 || parent->_bf == -1)

{

cur = parent;

parent = parent->_parent;

}

//_bf == 2/-2,說明AVL樹失衡,需要進(jìn)行旋轉(zhuǎn)操作

else if (parent->_bf == 2 || parent->_bf == -2)

{

//插入后AVl樹失衡,需要進(jìn)行平衡調(diào)整

}

}

return true;

}

private:

Node* _root = nullptr;;

};

AVL樹的平衡調(diào)整

AVL樹的調(diào)整其實(shí)就是對(duì)失衡的AVl樹進(jìn)行旋轉(zhuǎn)操作,旋轉(zhuǎn)操作必須保持搜索樹的規(guī)則,讓失衡的AVL樹變平衡。

旋轉(zhuǎn)操作可以分為4種:右單旋、左單旋、左右雙旋和右左雙旋。

右單旋

當(dāng)parent->_bf == -2 && cur->_bf == -1時(shí)說明AVL樹往左傾斜,需要進(jìn)行右單旋操作。

右單旋其實(shí)就是從樹的右邊將樹順時(shí)針旋轉(zhuǎn)。?? ??

?

void RotataR(Node* parent)

{

//subL為parent的左孩子節(jié)點(diǎn)

Node* subL = parent->_left;

//subLR為subL的右子節(jié)點(diǎn)

Node* SubLR = subL->_right;

// 將parent與subLR節(jié)點(diǎn)進(jìn)行鏈接

parent->_left = SubLR;

//在SubLR的情況下更改,讓其指向正確的父親

if (SubLR)

SubLR->_parent = parent;

//提前記錄祖父節(jié)點(diǎn)

Node* pParent = parent->_parent;

//鏈接subL與parent

subL->_right = parent;

parent->_parent = subL;

//根據(jù)parent是否是根節(jié)點(diǎn)進(jìn)行不同處理

if (parent == _root)

{

_root = subL;

subL->_parent = nullptr;

}

else

{

//將pParent和subL鏈接

//但得先判斷parent是pParent的左節(jié)點(diǎn)還是右節(jié)點(diǎn)

if (pParent->_left == parent)

pParent->_left = subL;

else

pParent->_right = subL;

//修改subL的parent指針,讓其指向正確的父親

subL->_parent = pParent;

}

//更新平衡因子

subL->_bf = parent->_bf = 0;

}

左單旋

當(dāng)parent->_bf == 2 && cur->_bf == 1時(shí)說明AVL樹往右傾斜,需要進(jìn)行左單旋操作。

左單旋其實(shí)就是從樹的左邊將樹逆時(shí)針旋轉(zhuǎn)。

?

?

void RotateL(Node* parent)

{

Node* subR = parent->_right;

Node* subRL = subR->_left;

parent->_right = subRL;

if (subRL)

subRL->_parent = parent;

Node* pParent = parent->_parent;

subR->_left = parent;

parent->_parent = subR;

if (parent == _root)

{

_root = subR;

subR->_parent = nullptr;

}

else

{

if (pParent->_left == parent)

pParent->_left = subR;

else

pParent->_right = subR;

subR->_parent = pParent;

}

subR->_bf = parent->_bf = 0;

}

左右雙旋

當(dāng)parent->_bf == -2 && cur->_bf == 1時(shí),即新節(jié)點(diǎn)插入到較高左子樹的右側(cè):先左單旋然后再右單旋。

左右雙旋情況比較復(fù)雜,如下圖。

void RotateLR(Node* parent)

{

Node* subL = parent->_left;

Node* subLR = subL->_right;

//記錄subLR的bf,根據(jù)其取值更新左右雙旋后各個(gè)節(jié)點(diǎn)的bf

int bf = subLR->_bf;

RotateL(subL);

RotateR(parent);

subLR->_bf = 0;

if (bf == -1)

{

subL->_bf = 0;

parent->_bf = 1;

}

else if (bf == 1)

{

subL->_bf = -1;

parent->_bf = 0;

}

else if (bf == 0)

{

subL->_bf = 0;

parent->_bf = 0;

}

else

assert(false);

}

右左雙旋

當(dāng)parent->_bf == 2 && cur->_bf == -1時(shí),即新節(jié)點(diǎn)插入到較高右子樹的左側(cè):先右單旋然后再左單旋。

右左雙旋其實(shí)就是左右雙旋的另一種情況,我們直接上圖解。

?

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 = 1;

parent->_bf = 0;

}

else if (bf == 1)

{

subR->_bf = 0;

parent->_bf = -1;

}

else if (bf == 0)

{

subR->_bf = 0;

parent->_bf = 0;

}

else

assert(false);

}

完整的插入函數(shù)

bool Insert(const pair& kv)

{

//空樹的情況特殊處理

if (_root == nullptr)

{

_root = new Node(kv);

return true;

}

//不是空樹的情況

Node* parent = nullptr;

Node* cur = _root;

//查找新節(jié)點(diǎn)的插入位置

while (cur)

{

parent = cur;

if (kv.first > cur->_kv.first)

cur = cur->_right;

else if (kv.first < cur->_kv.first)

cur = cur->_left;

else

return false;

}

cur = new Node(kv);

//將父節(jié)點(diǎn)與新節(jié)點(diǎn)鏈接

//判斷新節(jié)點(diǎn)插入到parent的左邊還是右邊

if (kv.first > parent->_kv.first) //新節(jié)點(diǎn)插入到parent的右邊

parent->_right = cur;

else

parent->_left = cur;

//更改新節(jié)點(diǎn)的父親指針

cur->_parent = parent;

//更新平衡因子

while (parent)

{

//插入節(jié)點(diǎn)后除了對(duì)父節(jié)點(diǎn)造成影響還可能對(duì)祖宗節(jié)點(diǎn)造成影響

//隨著循環(huán)進(jìn)行,cur不一定為新節(jié)點(diǎn)

//更新父節(jié)點(diǎn)的平衡因子

if (cur == parent->_left)

parent->_bf--;

else

parent->_bf++;

//檢查更新后父親的平衡因子

//_bf為0,說明樹還是AVL樹,退出循環(huán)

if (parent->_bf == 0)

break;

//_bf == 1/-1,說明需要繼續(xù)向上更新平衡因子

else if (parent->_bf == 1 || parent->_bf == -1)

{

cur = parent;

parent = parent->_parent;

}

//_bf == 2/-2,說明AVL樹失衡,需要進(jìn)行旋轉(zhuǎn)操作

else if (parent->_bf == 2 || parent->_bf == -2)

{

//插入后AVl樹失衡,需要進(jìn)行平衡調(diào)整

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

else

assert(false);

break;

}

else

assert(false);

}

return true;

}

AVL樹的查找

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

return cur;

}

return nullptr;

}

AVL樹的驗(yàn)證

驗(yàn)證有序

我們首先需要寫一個(gè)中序遍歷來看看插入的數(shù)據(jù)是否符合預(yù)期。

void InOrder()

{

_InOrder(_root);

cout << endl;

}

void _InOrder(Node* root)

{

if (root == nullptr)

return;

_InOrder(root->_left);

cout << root->_kv.first << ":" << root->_kv.second << endl;

_InOrder(root->_right);

}

我們來跑個(gè)測(cè)試用例。

void test_AVLTree1()

{

AVLTree avlT1;

AVLTree avlT2;

int a1[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 };

int a2[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 };

for (auto e : a1)

{

avlT1.Insert({ e, e });

}

for (auto e : a2)

{

avlT2.Insert({ e, e });

}

avlT1.InOrder();

avlT2.InOrder();

}

可以看到結(jié)果是沒問題的。

驗(yàn)證平衡

int Height()

{

return _Height(_root);

}

int _Height(Node* root)

{

if (root == nullptr)

return 0;

int LeftHeight = _Height(root->_left);

int RightHeight = _Height(root->_right);

return (LeftHeight > RightHeight ? LeftHeight : RightHeight) + 1;

}

bool IsBalanceTree()

{

return _IsBalanceTree(_root);

}

bool _IsBalanceTree(Node* root)

{

// 空樹也是AVL樹

if (root == nullptr)

return true;

// 計(jì)算pRoot結(jié)點(diǎn)的平衡因子:即Root左右子樹的高度差

int LeftHeight = _Height(root->_left);

int RightHeight = _Height(root->_right);

int diff = RightHeight - LeftHeight;

// 如果計(jì)算出的平衡因子與Root的平衡因子不相等,或者

// pRoot平衡因子的絕對(duì)值超過1,則一定不是AVL樹

if (abs(diff) >= 2)

{

cout << root->_kv.first << "高度異常" << endl;

return false;

}

if (root->_bf != diff)

{

cout << root->_kv.first << "平衡因子異常" << endl;

return false;

}

// pRoot的左和右如果都是AVL樹,則該樹一定是AVL樹

return _IsBalanceTree(root->_left) && _IsBalanceTree(root->_right);

我們用大量數(shù)據(jù)來測(cè)試下。

void test_AVLTree2()

{

const int N = 1000000;

vector v;

v.reserve(N);

srand((unsigned int)time(0));

for (size_t i = 0; i < N; i++)

{

v.push_back(rand() + i);

}

AVLTree t;

for (auto e : v)

{

t.Insert(make_pair(e, e));

}

if (t.IsBalanceTree())

cout << "是AVL樹" << endl;

else

cout << "不是AVL樹" << endl;

cout << "Height:" << t.Height() << endl;

cout << "Size:" << t.Size() << endl;

}

完整代碼

#include

#include

using namespace std;

template

struct AVLTreeNode

{

pair _kv;

AVLTreeNode* _left;

AVLTreeNode* _right;

AVLTreeNode* _parent;

int _bf;

AVLTreeNode(const pair& kv)

:_kv(kv)

, _left(nullptr)

,_right(nullptr)

,_parent(nullptr)

,_bf(0)

{}

};

template

class AVLTree

{

typedef AVLTreeNode Node;

public:

bool Insert(const pair& kv)

{

//空樹的情況特殊處理

if (_root == nullptr)

{

_root = new Node(kv);

return true;

}

//不是空樹的情況

Node* parent = nullptr;

Node* cur = _root;

//查找新節(jié)點(diǎn)的插入位置

while (cur)

{

parent = cur;

if (kv.first > cur->_kv.first)

cur = cur->_right;

else if (kv.first < cur->_kv.first)

cur = cur->_left;

else

return false;

}

cur = new Node(kv);

//將父節(jié)點(diǎn)與新節(jié)點(diǎn)鏈接

//判斷新節(jié)點(diǎn)插入到parent的左邊還是右邊

if (kv.first > parent->_kv.first) //新節(jié)點(diǎn)插入到parent的右邊

parent->_right = cur;

else

parent->_left = cur;

//更改新節(jié)點(diǎn)的父親指針

cur->_parent = parent;

//更新平衡因子

while (parent)

{

//插入節(jié)點(diǎn)后除了對(duì)父節(jié)點(diǎn)造成影響還可能對(duì)祖宗節(jié)點(diǎn)造成影響

//隨著循環(huán)進(jìn)行,cur不一定為新節(jié)點(diǎn)

//更新父節(jié)點(diǎn)的平衡因子

if (cur == parent->_left)

parent->_bf--;

else

parent->_bf++;

//檢查更新后父親的平衡因子

//_bf為0,說明樹還是AVL樹,退出循環(huán)

if (parent->_bf == 0)

break;

//_bf == 1/-1,說明需要繼續(xù)向上更新平衡因子

else if (parent->_bf == 1 || parent->_bf == -1)

{

cur = parent;

parent = parent->_parent;

}

//_bf == 2/-2,說明AVL樹失衡,需要進(jìn)行旋轉(zhuǎn)操作

else if (parent->_bf == 2 || parent->_bf == -2)

{

//插入后AVl樹失衡,需要進(jìn)行平衡調(diào)整

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

else

assert(false);

break;

}

else

assert(false);

}

return true;

}

void RotateR(Node* parent)

{

//subL為parent的左孩子節(jié)點(diǎn)

Node* subL = parent->_left;

//subLR為subL的右子節(jié)點(diǎn)

Node* subLR = subL->_right;

// 將parent與subLR節(jié)點(diǎn)進(jìn)行鏈接

parent->_left = subLR;

//在SubLR的情況下更改,讓其指向正確的父親

if (subLR)

subLR->_parent = parent;

//提前記錄祖父節(jié)點(diǎn)

Node* pParent = parent->_parent;

//鏈接subL與parent

subL->_right = parent;

parent->_parent = subL;

//根據(jù)parent是否是根節(jié)點(diǎn)進(jìn)行不同處理

if (parent == _root)

{

_root = subL;

subL->_parent = nullptr;

}

else

{

//將pParent和subL鏈接

//但得先判斷parent是pParent的左節(jié)點(diǎn)還是右節(jié)點(diǎn)

if (pParent->_left == parent)

pParent->_left = subL;

else

pParent->_right = subL;

//修改subL的parent指針,讓其指向正確的父親

subL->_parent = pParent;

}

//更新平衡因子

subL->_bf = parent->_bf = 0;

}

void RotateL(Node* parent)

{

Node* subR = parent->_right;

Node* subRL = subR->_left;

parent->_right = subRL;

if (subRL)

subRL->_parent = parent;

Node* pParent = parent->_parent;

subR->_left = parent;

parent->_parent = subR;

if (parent == _root)

{

_root = subR;

subR->_parent = nullptr;

}

else

{

if (pParent->_left == parent)

pParent->_left = subR;

else

pParent->_right = subR;

subR->_parent = pParent;

}

subR->_bf = parent->_bf = 0;

}

void RotateLR(Node* parent)

{

Node* subL = parent->_left;

Node* subLR = subL->_right;

//記錄subLR的bf,根據(jù)其取值更新左右雙旋后各個(gè)節(jié)點(diǎn)的bf

int bf = subLR->_bf;

RotateL(subL);

RotateR(parent);

subLR->_bf = 0;

if (bf == -1)

{

subL->_bf = 0;

parent->_bf = 1;

}

else if (bf == 1)

{

subL->_bf = -1;

parent->_bf = 0;

}

else if (bf == 0)

{

subL->_bf = 0;

parent->_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);

subRL->_bf = 0;

if (bf == -1)

{

subR->_bf = 1;

parent->_bf = 0;

}

else if (bf == 1)

{

subR->_bf = 0;

parent->_bf = -1;

}

else if (bf == 0)

{

subR->_bf = 0;

parent->_bf = 0;

}

else

assert(false);

}

void InOrder()

{

_InOrder(_root);

cout << endl;

}

int Height()

{

return _Height(_root);

}

int Size()

{

return _Size(_root);

}

bool IsBalanceTree()

{

return _IsBalanceTree(_root);

}

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

return cur;

}

return nullptr;

}

private:

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 LeftHeight = _Height(root->_left);

int RightHeight = _Height(root->_right);

return (LeftHeight > RightHeight ? LeftHeight : RightHeight) + 1;

}

int _Size(Node* root)

{

if (root == nullptr)

return 0;

return _Size(root->_left) + _Size(root->_right) + 1;

}

bool _IsBalanceTree(Node* root)

{

// 空樹也是AVL樹

if (root == nullptr)

return true;

// 計(jì)算pRoot結(jié)點(diǎn)的平衡因子:即Root左右子樹的高度差

int LeftHeight = _Height(root->_left);

int RightHeight = _Height(root->_right);

int diff = RightHeight - LeftHeight;

// 如果計(jì)算出的平衡因子與Root的平衡因子不相等,或者

// pRoot平衡因子的絕對(duì)值超過1,則一定不是AVL樹

if (abs(diff) >= 2)

{

cout << root->_kv.first << "高度異常" << endl;

return false;

}

if (root->_bf != diff)

{

cout << root->_kv.first << "平衡因子異常" << endl;

return false;

}

// pRoot的左和右如果都是AVL樹,則該樹一定是AVL樹

return _IsBalanceTree(root->_left) && _IsBalanceTree(root->_right);

}

private:

Node* _root = nullptr;

};

拜拜,下期再見?

摸魚ing???

柚子快報(bào)激活碼778899分享:算法 C++:AVL樹

http://yzkb.51969.com/

參考鏈接

評(píng)論可見,查看隱藏內(nèi)容

本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點(diǎn)和立場(chǎng)。

轉(zhuǎn)載請(qǐng)注明,如有侵權(quán),聯(lián)系刪除。

本文鏈接:http://gantiao.com.cn/post/19871125.html

發(fā)布評(píng)論

您暫未設(shè)置收款碼

請(qǐng)?jiān)谥黝}配置——文章設(shè)置里上傳

掃描二維碼手機(jī)訪問

文章目錄