1.AVL树的概念及作用
2.AVL树插入数据的规则
1.按照搜索树的规则插入,然后更新父亲的平衡因子
2.更新父亲的平衡因子后,如果出现一下三种情况需要进行相应处理
3.AVL树的旋转
3.1右单旋
右单旋的所有情况可以抽象为上图:图中,a,b,c均为高度为h(h取0,1,2......)的AVL子树。
插入新结点后,开始旋转:parent->left=subLR; subL->right=parent;
旋转过后依然满足搜索树的规则。
但旋转并没有那么简单,还要调整父子关系,调整根结点,更新平衡因子!
代码:
//右单旋
void RotateR(Node* parent) {
//旋转,改变树形结构
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
subL->_right = parent;
//调整父子关系
Node* ppNode = parent->_parent;
if (subLR) subLR->_parent = parent;
parent->_parent = subL;
//处理根节点
if (parent==_root) {
_root = subL;
subL->_parent = nullptr;
}
else {
subL->_parent == ppNode;
if (ppNode->_left == parent) ppNode->_left = subL;
else ppNode->_right = subL;
}
//更新平衡因子
subL->_bf = parent->_bf = 0;
}
3.2左单旋
思路和代码与右单旋类似。
void RotateL(Node* parent) {
//旋转,改变树形结构
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
subR->_left = parent;
//调整父子关系
Node* ppNode = parent->_parent;
if (subRL) subRL->_parent = parent;
parent->_parent = subR;
//处理根节点
if (parent == _root) {
_root = subR;
subR->_parent = nullptr;
}
else {
subR->_parent = ppNode;
if (ppNode->_left == parent) ppNode->_left = subR;
else ppNode->_right = subR;
}
//更新平衡因子
subR->_bf = parent->_bf = 0;
}
3.3左右双旋
对比一下右单旋的图片,左右双旋的抽象图是把30结点的右子树细致的分为60的结点和60的左右子树。
双旋的情况就是在60这个子树上插入一个新的结点,插入过后需要经过两次旋转。旋转后的结果就是30和90都变成了60的子树。原本为60的子树,变成了30和90的子树。
代码:
//左右双旋
void RotateLR(Node* parent) {
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(parent->_left);
RotateR(parent);
subLR->_bf = 0;
if (bf == 0) {
parent->_bf = 0;
subL->_bf = 0;
}
else if (bf == 1) {
parent->_bf = 0;
subL->_bf = -1;
}
else if (bf == -1) {
parent->_bf = 1;
subL->_bf = 0;
}
else assert(false);//理论上不存在这种情况
}
3.4右左双旋
右左双旋与左右双旋正好相反。
代码:
//右左双旋
void RotateRL(Node* parent) {
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(parent->_right);
RotateL(parent);
subRL->_bf = 0;
if (bf == 0) {
parent->_bf = 0;
subR->_bf = 0;
}
else if (bf == 1) {
parent->_bf = -1;
subR->_bf = 0;
}
else if (bf == -1) {
parent->_bf = 0;
subR->_bf = 1;
}
else assert(false);//理论上这种情况不存在
}
4.AVL树的底层
模拟实现:
其中:AVLTree_Test1()和AVLTree_Test2()为测试代码。
#pragma once
#include<iostream>
using namespace std;
#include<assert.h>
#include<vector>
//KV模型
namespace key_value {
template<class k, class v>
//class BinarySearchTreeNode
struct AVLTreeNode {
AVLTreeNode(const pair<k,v>& kv)
:_kv(kv)
{}
AVLTreeNode<k, v>* _left = nullptr;
AVLTreeNode<k, v>* _right = nullptr;
AVLTreeNode<k, v>* _parent = nullptr;
pair<k, v> _kv;
int _bf = 0;//balance factor
};
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) break;
else if (parent->_bf == 1 || parent->_bf == -1) {
cur = parent;
parent = parent->_parent;
}
else if (parent->_bf == 2 || parent->_bf == -2) {
//旋转
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 assert(false);
}
return true;
}
void Inorder() {
_Inorder(_root);
}
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 RotateR(Node* parent) {
//旋转,改变树形结构
Node* subL = parent->_left;
Node* subLR = subL->_right;
parent->_left = subLR;
subL->_right = parent;
//调整父子关系
Node* ppNode = parent->_parent;
if (subLR) subLR->_parent = parent;
parent->_parent = subL;
//处理根节点
if (parent==_root) {
_root = subL;
subL->_parent = nullptr;
}
else {
subL->_parent = ppNode;
if (ppNode->_left == parent) ppNode->_left = subL;
else ppNode->_right = subL;
}
//更新平衡因子
subL->_bf = parent->_bf = 0;
}
void RotateL(Node* parent) {
//旋转,改变树形结构
Node* subR = parent->_right;
Node* subRL = subR->_left;
parent->_right = subRL;
subR->_left = parent;
//调整父子关系
Node* ppNode = parent->_parent;
if (subRL) subRL->_parent = parent;
parent->_parent = subR;
//处理根节点
if (parent == _root) {
_root = subR;
subR->_parent = nullptr;
}
else {
subR->_parent = ppNode;
if (ppNode->_left == parent) ppNode->_left = subR;
else ppNode->_right = subR;
}
//更新平衡因子
subR->_bf = parent->_bf = 0;
}
//右左双旋
void RotateRL(Node* parent) {
Node* subR = parent->_right;
Node* subRL = subR->_left;
int bf = subRL->_bf;
RotateR(parent->_right);
RotateL(parent);
subRL->_bf = 0;
if (bf == 0) {
parent->_bf = 0;
subR->_bf = 0;
}
else if (bf == 1) {
parent->_bf = -1;
subR->_bf = 0;
}
else if (bf == -1) {
parent->_bf = 0;
subR->_bf = 1;
}
else assert(false);//理论上这种情况不存在
}
//左右双旋
void RotateLR(Node* parent) {
Node* subL = parent->_left;
Node* subLR = subL->_right;
int bf = subLR->_bf;
RotateL(parent->_left);
RotateR(parent);
subLR->_bf = 0;
if (bf == 0) {
parent->_bf = 0;
subL->_bf = 0;
}
else if (bf == 1) {
parent->_bf = 0;
subL->_bf = -1;
}
else if (bf == -1) {
parent->_bf = 1;
subL->_bf = 0;
}
else assert(false);//理论上不存在这种情况
}
bool IsBalance() {
return _IsBalance(_root);
}
int Height() {
return _Height(_root);
}
int Size() {
return _size(_root);
}
private:
int _size(Node* root) {
if (root == nullptr) return 0;
return _size(root->_left) + _size(root->_right) + 1;
}
int _Height(Node* root) {
if (root == nullptr) return 0;
else
return max(_Height(root->_left), _Height(root->_right)) + 1;
}
bool _IsBalance(Node* root) {
if (root == nullptr) return true;
else {
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);
}
private:
Node* _root = nullptr;
};
}
void AVLTree_Test1() {
//int arr[] = { 8,3,1,10,6,4,7,14,13 };
int arr[] = { 4,2,6,1,3,5,15,7,16,14 };
key_value::AVLTree<int, int> t1;
for (auto& e : arr) {
/*if (e == 4) {
int i = 0;
}*/
t1.insert({e,e});
}
t1.Inorder();
cout << t1.IsBalance() << endl;
}
void AVLTree_Test2() {
const int N = 1000000;
vector<int> v;
srand(time(0));
for (int i = 0; i < N; i++) {
v.push_back(rand()+i);
}
size_t begin1 = clock();
key_value::AVLTree<int, int> t;
for (auto e : v) {
t.insert(make_pair(e, e));
}
size_t end1 = clock();
size_t begin2 = clock();
for (auto e : v) {
t.Find(e);
}
size_t end2 = clock();
cout <<"insert"<<"->"<< end1 - begin1 << endl;
cout << "Balance->"<<t.IsBalance() << endl;
cout << "Height->" << t.Height() << endl;
cout << "Size->" << t.Size() << endl;
cout << "Find->" << end2 - begin2 << endl;
}
测试:
#include"AVLTree.h"
int main() {
//AVLTree_Test1();
AVLTree_Test2();
return 0;
}
从程序运行结果可知:在Release版本下,插入100万个随机数,其中实际插入约63万个数值。
插入耗时:173毫秒(主要是new结点花时间)。
AVL树高度:22。
把63万个随机数全部查找一遍耗时:不到1毫秒。
可见AVL树的查找效率是非常高的!