AVL树
来源:互联网 发布:apache ant windows 编辑:程序博客网 时间:2024/05/29 19:59
AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个子树的高度最大差别为一,所以它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。
AVL树是建立在二叉搜索树的基础之上的,因为二叉树搜索树有缺陷
当我们的二叉搜索树是如上图的样子,那么它是顺序查找,在它的最坏情况下 时间复杂度是O( N),在这种情况下如果我们数据特别多,那么效率太低。而这种问题是因为它的左右子树的高度差极度不平衡造成的。
为了解决这种问题因此引入了AVL树,AVL树自身也是满足搜索二叉树的性质的,只不过它在左右子树高度差不平衡的时候会进行调整
AVL树的性质
1. 左子树和右子树的高度之差的绝对值不超过1 2. 树中的每个左子树和右子树都是AVL树 3. 每个节点都有一个平衡因子(balance factor–bf),任一节点的平衡因子是-1,0,1。(每个节点的平衡因子等于右子树的高度减去左子 树的高度 )
而AVL树的插入和删除它的时间复杂度都是O(logN)
AVL树的插入操作
由于AVL树的插入需要插入节点的父亲的信息,因此AVL树要维护的是一个个具有三叉链结构的节点,而之前普通的搜索二叉树维护的只是一个二叉链结构的 节点
因此AVL树较为普通的搜索二叉树较难
1、父节点的|bf|==2进行旋转
2、父节点的|bf|==1高度增加,向上更新平衡因子
3、父节点的|bf|==0,停止更新平衡因子
对于旋转又分为4种情况:
1、左单旋
2、右单旋
3、左右双旋
4、右左双旋
1、左单旋:
左单旋的代码就可以根据上图写出来
void RotateL( Node*&parent) { Node*SubR = parent->_right; Node*SubRL = SubR->_left; parent->_right = SubRL; if (SubRL) { SubRL->_parent = parent; } SubR->_left = parent; Node*ppNode = parent->_parent; parent->_parent = SubR; if (ppNode == NULL) { _root = SubR; _root->_parent = NULL; } else//考虑这个parent节点可能不是根节点 { if (parent == ppNode->_left) { ppNode->_left = SubR; } else { ppNode->_right = SubR; } SubR->_parent = ppNode; } parent->_bf = SubR->_bf = 0; }
2、右单旋:
右单旋的代码就可以根据上图写出来
void RotateR(Node*&parent) { Node*SubL = parent->_left; Node*SubLR = SubL->_right; parent->_left = SubLR; if (SubLR) { SubLR->_parent = parent; } SubL->_right = parent; Node*ppNode = parent->_parent;//不确定parent这个节点是不是根节点,要做判断,因此不能随意链接 parent->_parent = SubL; if (ppNode == NULL) { _root = SubL; _root->_parent = NULL; } else { if (parent == ppNode->_left) { ppNode->_left = SubL; } else { ppNode->_right = SubL; } SubL->_parent = ppNode; } SubL->_bf = parent->_bf = 0; }
3、左右双旋
代码如下:
void RotateLR(Node*parent) { RotateL(parent->left); RotateR(parent); }
这个代码是有问题的没有考虑特殊情况
因此修改代码
void RotateLR(Node*parent) { Node*SubL = parent->_left; Node*SubLR = SubL->_right; int Prebf = SubLR->_bf; RotateL(SubL); RotateR(parent); if (Prebf == -1) { SubL->_bf = 0; parent->_bf = 1; } else if (Prebf == 1) { SubL->_bf = -1; parent->_bf = 0; } else { parent->_bf = SubL->_bf = 0; } SubLR->_bf = 0; }
4、右左双旋
同左右双旋原理一样
代码如下
void RotateRL(Node*parent) { RotateR(parent->_right); RotateL(parent); }
但是这个代码是有问题的没有考虑特殊情况
当然这幅图我们也只是考虑了新增节点之后10的平衡因子为1,同左右双旋一样还要考虑10为0或者1的情况(这样考虑是因为10的父亲的祖父的平衡因子会随着10的变化而变化
因此修改代码
void RotateRL(Node*parent) { Node*SubR = parent->_right; Node*SubRL = SubR->_left; int Prebf = SubRL->_bf; RotateR(SubR); RotateL(parent); if (Prebf == -1) { SubR->_bf = 1; parent->_bf = 0; } else if (Prebf == 1) { SubR->_bf = 0; parent->_bf = -1; } else { parent->_bf = SubR->_bf = 0; } SubRL->_bf = 0; }
完整代码:
#include<iostream>#include<stdlib.h>using namespace std;template<class K,class V>struct AVLTreeNode{ AVLTreeNode(const K &key,const V&value=0) :_left(NULL) , _right(NULL) , _parent(NULL) , _key(key) , _value(value) , _bf(0) { } AVLTreeNode<K,V>*_left; AVLTreeNode<K, V>*_right; AVLTreeNode<K, V>*_parent; K _key; V _value; int _bf;};template<class K,class V>class AVLTree{ typedef AVLTreeNode<K, V> Node;public: AVLTree() :_root(NULL) { } bool Insert(const K &key,const V&value) { if (_root == NULL) { _root = new Node(key, value); return true; } else { Node*cur = _root; Node*parent = NULL; while (cur) { if (cur->_key > key)//和BS一样 { parent = cur; cur = cur->_left; } else if (cur->_key < key) { parent = cur; cur = cur->_right; } else { return false; } } cur = new Node(key, value); if (key > parent->_key) { parent->_right = cur; cur->_parent = parent; } else { parent->_left = cur; cur->_parent = parent; } //节点插入完成 //在插入节点之后进行平衡因子的调节,分情况进行处理 while (parent)//一直到调整到根节点为空为止 { if (cur == parent->_left) { parent->_bf--; } else if (cur == parent->_right) { parent->_bf++; } if (parent->_bf ==2||parent->_bf==-2)//进行旋转,旋转又分为4种 { if (parent->_bf == -2) { if (parent->_left->_bf == 1) { RotateLR(parent); return true; } else if (parent->_left->_bf == -1) { RotateR(parent); return true; } } else { if (parent->_right->_bf == 1) { RotateL(parent); return true; } else if (parent->_right->_bf == -1) { RotateRL(parent); return true; } } } else if (parent->_bf == 1 || parent->_bf == -1)//继续向上调整 { cur = parent; parent = parent->_parent; } else { break;//停止更新 } } } return true; } void RotateL( Node*&parent) { Node*SubR = parent->_right; Node*SubRL = SubR->_left; parent->_right = SubRL; if (SubRL) { SubRL->_parent = parent; } SubR->_left = parent; Node*ppNode = parent->_parent; parent->_parent = SubR; if (ppNode == NULL) { _root = SubR; _root->_parent = NULL; } else//考虑这个parent节点可能不是根节点 { if (parent == ppNode->_left) { 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; } SubL->_right = parent; Node*ppNode = parent->_parent;//不确定parent这个节点是不是根节点,要做判断,因此不能随意链接 parent->_parent = SubL; if (ppNode == NULL) { _root = SubL; _root->_parent = NULL; } else { if (parent == ppNode->_left) { 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 Prebf = SubLR->_bf; RotateL(SubL); RotateR(parent); if (Prebf == -1) { SubL->_bf = 0; parent->_bf = 1; } else if (Prebf == 1) { SubL->_bf = -1; parent->_bf = 0; } else { parent->_bf = SubL->_bf = 0; } SubLR->_bf = 0; } void RotateRL(Node*parent) { Node*SubR = parent->_right; Node*SubRL = SubR->_left; int Prebf = SubRL->_bf; RotateR(SubR); RotateL(parent); if (Prebf == -1) { SubR->_bf = 1; parent->_bf = 0; } else if (Prebf == 1) { SubR->_bf = 0; parent->_bf = -1; } else { parent->_bf = SubR->_bf = 0; } SubRL->_bf = 0; } bool IsBalance() { int depth = 0; return _IsBalance(_root);//判断是否为AVL树 } void InOrder()//中序遍历并不能检测是否是AVL树 { _InOrder(_root); } int Hight(Node*root) { if (root == NULL) { return 0; } int leftHight = Hight(root->_left); int rightHight = Hight(root->_right); return leftHight > rightHight ? (leftHight + 1) : (rightHight + 1); } bool _IsBalance(Node*root)//时间复杂度为n^2 { if (root == NULL) { return true; } int leftHight = Hight(root->_left); int rightHight = Hight(root->_right); int sub = rightHight - leftHight; if (abs(sub)>1||(sub) != root->_bf) { cout<<"异常为"<<root->_key<<" "<<root->_bf << endl; return false; } return abs(rightHight - leftHight) < 2 && _IsBalance(root->_left) && _IsBalance(root->_right); } bool _IsBalancePost(Node*root, int &depth)//采用时间复杂度为O(N)的算法 { if (root == NULL) { depth = 0; return true; } int LeftDepth; int RightDepth; if (!_IsBalancePost(root->_left, LeftDepth)) { return false; } if (!_IsBalancePost(root->_right, RightDepth)) { return false; } int diff = RightDepth - LeftDepth; if (diff > 1 || diff<-1||diff!=root->_bf) { cout << "平衡因子异常:"; cout << root->_key<<" ,"<<root->_bf << endl; return false; } depth = RightDepth - LeftDepth>0 ? RightDepth+1 : LeftDepth +1; return true; }protected: void _InOrder(Node*root) { if (root == NULL) { return; } _InOrder(root->_left); cout << root->_key << " "; _InOrder(root->_right); } Node*_root;};void FunTest1(){ //4, 2, 6, 1, 3, 5, 15, 7, 16, 14 //{16, 3, 7, 11, 9, 26, 18, 14, 15} AVLTree<int, int>av; int arr[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 }; for (int i = 0; i<(sizeof(arr) / sizeof(arr[0]));i++) { av.Insert(arr[i],i); cout << av.IsBalance() << endl; } cout << "IsBalance is "; av.InOrder();}void FunTest2(){ AVLTree<int, int>av; int arr[] = { 4, 2, 6, 1, 3, 5, 15, 7, 16, 14 }; for (int i = 0; i<(sizeof(arr) / sizeof(arr[0])); i++) { av.Insert(arr[i],i); cout<<av.IsBalance()<<endl; } cout << "IsBalance is "; av.InOrder();}int main(){ FunTest1(); system("pause"); return 0;}
- AVL树
- AVL树
- AVL树
- avl树
- AVL树
- avl树
- AVL树
- AVL树
- AVL树
- AVL树
- avl树
- avl树
- AVL树
- AVL树
- AVL树
- AVL树
- AVL 树
- AVL树
- 为什么用 Unity 3D 开发游戏是用 C# || JS 开发而不是用C++
- 0.1 bibi在前面的话+自我介绍
- 向往美好与面对现实
- Cake
- 整理:几款好用的Markdown编辑器
- AVL树
- Palindrome Centers Manacher算法
- 定义指针类型时*号位置与功能的关系
- canvas总结:线段宽度与像素边界
- POJ2965-The Pilots Brothers' refrigerator
- 算法练习笔记(十一)— 动态规划之分解问题
- python matplotlib imshow无法显示的问题
- 欢迎使用CSDN-markdown编辑器
- 白盒测试