目录
1、AVL树的概念
2、二叉搜索树的功能与实现
1、AVL树节点定义
2、AVL树的插入
3、AVL树的旋转操作
1、左旋
2、右旋
3、左右旋
4、右左旋
3、AVL树完整代码实现
1、AVL树的概念
在前面的文章中,我们学过了二叉搜索树,二叉搜索树虽可以缩短查找的效率,但如果数据有序或接近有序二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。因此,两位俄罗斯的数学家G.M.Adelson-Velskii 和E.M.Landis在1962年 发明了一种解决上述问题的方法:当向二叉搜索树中插入新结点后,如果能保证每个结点的左右 子树高度之差的绝对值不超过1(需要对树中的结点进行调整),即可降低树的高度,从而减少平均搜索长度。
它的左右子树都是 AVL 树左右子树高度之差 ( 简称平衡因子 ) 的绝对值不超过 1(-1/0/1)平衡因子:右子树高度减去左子树高度
2、二叉搜索树的功能与实现
1、AVL树节点定义
template<class K,class V>struct AVLTreeNode{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;int _bf; //平衡因子pair<K, V> _kv;AVLTreeNode(const pair<K, V>& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _bf(0),_kv(kv){}};
2、AVL树的插入
AVL树是在二叉搜索树的基础上引入了平衡因子,因此AVL树也可以看作二叉搜索树
插入过程与二叉搜索树一致,只不过要注意更新节点的平衡因子。
因为平衡因子是右子树高度减去左子树高度,所以如果在左子树添加节点,bf(平衡因子)--,在右子树添加,bf++。
parent节点的平衡因子更新有三种情况:
1、parent的平衡因子为0,说明满足AVL性质,插入成功。
2、parent的平衡因子为1或-1,说明该树的高度增加,需要向上更新。
3、parent的平衡因子为-2或2,说明该节点违反了平衡树性质,需要对其进行旋转处理。
旋转处理下面会介绍,我们先来看插入的代码实现:
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 = cur->_parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2){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{RotateRL(parent);}break;}else{assert(false);}}return true;}
寻找插入位置与搜索二叉树一致,然后更新平衡因子 ,对于不同的违反AVL树性质需要不同的旋转操作。
3、AVL树的旋转操作
1、左旋
void RotateL(Node* parent){Node* sub = parent->_right;Node* subl = sub->_left;parent->_right = subl;if (subl){subl->_parent = parent;}sub->_left = parent;Node* ppnode = parent->_parent;parent->_parent = sub;if (parent == _root){_root = sub;sub->_parent = nullptr;}else{if (parent == ppnode->_left){ppnode->_left = sub;}else{ppnode->_right = sub;}sub->_parent = ppnode;}parent->_bf = 0;sub->_bf = 0;}
2、右旋
原理与左旋相似,不过是向右旋转而已 (a,b,c具有相同的高度)
void RotateR(Node* parent){Node* sub = parent->_left;Node* subr = sub->_right;parent->_left = subr;if (subr){subr->_parent = parent;}sub->_right = parent;Node* ppnode = parent->_parent;parent->_parent = sub;if (parent == _root){_root = sub;sub->_parent = nullptr;}else{if (parent == ppnode->_left){ppnode->_left = sub;}else{ppnode->_right = sub;}sub->_parent = parent;}parent->_bf = 0;sub->_bf = 0;}
3、左右旋
先以subl为根左旋,再以parent为根进行右旋。(a,b,c具有相同的高度)
void RotateLR(Node* parent){Node* subl = parent->_left;Node* sublr = subl->_right;int bf = sublr->_bf;RotateL(subl);RotateR(parent);if (bf == -1){sublr->_bf = 0;parent->_bf = 1;subl->_bf = 0;}else if (bf == 1){sublr->_bf = 0;parent->_bf = 0;subl->_bf = -1;}else if (bf == 0){subl->_bf = 0;parent->_bf = 0;sublr->_bf = 0;}else{assert(false);}}
根据sublr的平衡因子的不同(也就是插入到了B还是C)来判断如何更新平衡因子。
4、右左旋
原理与左右旋相似,只是换了个方向。(a,b,c具有相同的高度)
void RotateRL(Node* parent){Node* subr = parent->_right;Node* subrl = subr->_left;int bf = subrl->_bf;RotateR(subr);RotateL(parent);if (bf == -1){subrl->_bf = 0;parent->_bf = 0;subr->_bf = 1;}else if (bf == 1){subrl->_bf = 0;parent->_bf = -1;subr->_bf = 0;}else if(bf==0){subrl->_bf = 0;parent->_bf = 0;subr->_bf = 0;}else{assert(false);}}
根据sublr的平衡因子的不同(也就是插入到了B还是C)来判断如何更新平衡因子。
3、AVL树完整代码实现
内部包含查找以及判断是否是AVL树的函数,以及中序遍历。
#pragma once
namespace AVLTree_test
{template<class K,class V>struct AVLTreeNode{AVLTreeNode<K, V>* _left;AVLTreeNode<K, V>* _right;AVLTreeNode<K, V>* _parent;int _bf; //平衡因子pair<K, V> _kv;AVLTreeNode(const pair<K, V>& kv):_left(nullptr), _right(nullptr), _parent(nullptr), _bf(0),_kv(kv){}};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 = cur->_parent;parent = parent->_parent;}else if (parent->_bf == 2 || parent->_bf == -2){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{RotateRL(parent);}break;}else{assert(false);}}return true;}void RotateL(Node* parent){Node* sub = parent->_right;Node* subl = sub->_left;parent->_right = subl;if (subl){subl->_parent = parent;}sub->_left = parent;Node* ppnode = parent->_parent;parent->_parent = sub;if (parent == _root){_root = sub;sub->_parent = nullptr;}else{if (parent == ppnode->_left){ppnode->_left = sub;}else{ppnode->_right = sub;}sub->_parent = ppnode;}parent->_bf = 0;sub->_bf = 0;}void RotateR(Node* parent){Node* sub = parent->_left;Node* subr = sub->_right;parent->_left = subr;if (subr){subr->_parent = parent;}sub->_right = parent;Node* ppnode = parent->_parent;parent->_parent = sub;if (parent == _root){_root = sub;sub->_parent = nullptr;}else{if (parent == ppnode->_left){ppnode->_left = sub;}else{ppnode->_right = sub;}sub->_parent = parent;}parent->_bf = 0;sub->_bf = 0;}void RotateLR(Node* parent){Node* subl = parent->_left;Node* sublr = subl->_right;int bf = sublr->_bf;RotateL(subl);RotateR(parent);if (bf == -1){sublr->_bf = 0;parent->_bf = 1;subl->_bf = 0;}else if (bf == 1){sublr->_bf = 0;parent->_bf = 0;subl->_bf = -1;}else if (bf == 0){subl->_bf = 0;parent->_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){subrl->_bf = 0;parent->_bf = 0;subr->_bf = 1;}else if (bf == 1){subrl->_bf = 0;parent->_bf = -1;subr->_bf = 0;}else if(bf==0){subrl->_bf = 0;parent->_bf = 0;subr->_bf = 0;}else{assert(false);}}void _InOrder(Node* root){if (root == nullptr)return;_InOrder(root->_left);cout << root->_kv.first << " " << root->_bf << endl;_InOrder(root->_right);}void InOrder(){_InOrder(_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 _IsBalance(Node* root){if (root == nullptr)return true;int leftHeight = Height(root->_left);int rightHeight = Height(root->_right);if (abs(rightHeight - leftHeight) >= 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);}bool IsBalance(){return _IsBalance(_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 NULL;}private:Node* _root = nullptr;};void TestAVLTree1(){int a[] = { 4, 2, 6, 1,0 ,67,56,33,212,90};AVLTree<int, int> t;for (auto e : a){if (e == 14){int x = 0;}t.Insert(make_pair(e,e));}t.InOrder();cout << t.IsBalance();}
}