平衡搜索树:AVLTree的实现
来源:互联网 发布:快递热敏打印软件 编辑:程序博客网 时间:2024/05/21 16:12
为什么使用AVLTree?
对于一般的搜索二叉树而言,在理想的状态下,寻找一个数的复杂度为o(lgn)(这个树为满二叉树),最坏为o(n),如下图所示:
所以我们需要限制它的左右高度,防止它出现不平衡状态。
AVL树的性质
1. 左子树和右子树的高度之差的绝对值不超过1
2. 树中的每个左子树和右子树都是AVL树
3. 每个节点都有一个平衡因子(我用br表示),任一节点的平衡因子是-1,0,1。(每个节点的平衡因子等于右子树的高度减去左子树的高度 )
AVL树的难点在于如何维护AVL树的性质,以及正确的更新节点的平衡因子。我们一般使用旋转的方法来维护。
如果你还对节点之间的旋转不太清楚的话,你可以看看这篇博客:http://blog.csdn.net/fengasdfgh/article/details/52917671
现在我们主要讨论插入时的情况(删除可以看作是插入的逆向,你学会了insert,就可以自己琢磨出erase)。
在这里你还可能对平衡因子的作用没有什么感触,为了引起你的重视,我在这里说明平衡因子的意义。
就如性质3所说的,平衡因子为节点的左右高度差,它可能的值如下:
1 : 说明该节点的右子树比左子树高度高1.
0 : 右子树和左子树一样高。
-1 : 左子树比右子树高1.
2 : 右子树高度比左子树高度高2,这已经违背了性质 1,我们必须 通过旋转来调整这个子树来维持性质。
-2 : 左子树比右子树高2,这同样也违背了性质1.
我们重点讨论新节点插入后怎么更新节点的br(平衡因子)以及如何维护性质1.
首先我们可以推出新节点的br为0.
如果你以为这就结束了,那未免也太简单了。新插入的节点会导致其父节点的左右高度差改变,继而父节点的平衡因子改变。
那么这种改变如果影响到了其祖先节点的左右高度差改变,它是否会影响到其祖先节点那?
我们又如何去判断?
什么时候不会修改?
如果修改了,怎么去更新它的br值?
我用图片说明:
如图中所示:因为d节点的插入,因为d是c的右节点,说明c的右子树高度一定发生了变化,所以c的平衡因子发生了变化。
注意,因为c的平衡因子发生变化,那么对于节点b来说,b的右子树高度一定发生变化,所以它的平衡因子发生变化。
既然b的平衡因子改变了,为什么没有影响到a?因为b的平衡因子变为了0,这说明它的左右子树高度相等,但这对于a来说,它的右子树高度是没有变的,a的左右子树高度都没变,则它的平衡因子不会变。
比如:在d点插入之前各点状况如下:
左子树高度 右子树高度
a 2 3
b 2 1
c 0 0
d点插入之后
左子树高度 右子树高度
a 2 3
b 2 2
c 0 1
这里我们可以总结出规律:
如果一个点的平衡因子发生变化且变为1,-1,那么它一定对它的父节点产生了影响,是0则不然。
可以看出对平衡因子的调节是一个从下向上调整的过程。
void adjust(Node *child)//调整函数 { Node *father = child->_father; //从孩子到父亲,向上调整。 while (child != _root) { if (father->_left == child) father->_br -= 1; else father->_br += 1; if (0 == father->_br) break; else if (1 == father->_br || -1 == father->_br) { child = father; father = father->_father; } } }
如果你认为这就完了,那么再请拉回去看一下平衡因子还有可能的取值,没错我们还没有讨论平衡因子为2,-2时的状况。
平衡因子变为2,-2,这说明这棵树(具体地说是这棵子树,但它会导致这棵树不为AVLTree)不是AVLTree.那么我们就需要来维护这个二叉树了。如图:
类似的,在右子树插入也是一样的。
我们设新插入的节点为child,则它的父亲为为father。
我们可以从上面找到以下规律;
此时说到的br(平衡因子)值都已经是更新过的,我们从新插入的结点开始向上更新,遇到有节点的br值为2,-2时边调用旋转函数,遇到0
终止,遇到1,-1继续向上调节。
while child != root //最多到达根节点//更新father的br值代码此处省略//判断father更新后的br值if father的br(平衡因子值)为2 if father的br为1 进行左旋; else 进行右左双旋;else if father的br(平衡因子值)为-2 if father的br为-1 进行右旋; else 进行左右双旋; else if father的br(平衡因子值)为1,-1 child = father;else break;
C++代码如下:
void adjust(Node *child) { Node *father = child->_father; while (child != _root) { if (father->_left == child) father->_br -= 1; else father->_br += 1; if (0 == father->_br) break; else if (1 == father->_br || -1 == father->_br) { child = father; father = father->_father; } else { adjust(child, father); break; } } } void adjust(Node *father, Node *grandfather) { if (2 == grandfather->_br)//进行左旋转 { if (-1 == father->_br)//进行右左旋转 { rotate_right_left(father); //调整相关节点的高度因子 father->_br = grandfather->_br = 0; } else { rotate_left(father); father->_br = grandfather->_br = 0; } } else if (-2 == grandfather->_br)//进行右旋转 { if (1 == father->_br)//进行左右旋转 { rotate_left_right(father); //调整相关节点的高度因子 father->_br = grandfather->_br = 0; } else { rotate_right(father); father->_br = grandfather->_br = 0; } } }
基本上到这里就可以说AVL树基本完成了,但是这样没问题吗?我们可以测试一下,思路是我们在构造完AVL树后,对每个节点进行遍历,
判断它的左右子树高度差righthigh- lefthigh是否不超过1.并且也判断是否等于该节点的br值。
判断函数如下:
bool Isblance() { int height = 0; return Isblance(_root, height); } bool Isblance(Node *root, int& height) { if (NULL == root) { return true; height = 0; } int leftmax = 0; //判断左右子树是否平横 if (!Isblance(root->_left, leftmax)) return false; int rightmax = 0; if (!Isblance(root->_right, rightmax)) return false; //判断该节点的平衡因子值是否正确,把所有平衡因子错误的节点打印出来。 if (root->_br != rightmax - leftmax) { cout << "don't blance" << ends; cout << root->_key << endl; } //判断该子树是否平横 if (abs(rightmax - leftmax) >= 2) return false; height = (max(leftmax, rightmax)) + 1; return true; }
测试函数如下:
void test()
{
AVLtree<int, int> a;vector<int> Test = {4, 2, 6, 1, 3, 5, 15, 7, 16 ,14};for (auto p : Test){ a.insert(p);}a.Inorder();//中序遍历a.Isblance() ? cout << "blance" << endl : cout << "noblance" << endl;
}
结果如下(vs2015):
好吧,这里出现了问题,虽然这棵树现在的结构正确,但它节点的平衡因子已经有了问题,这势必会有隐患。
我们现在需要知道哪里出现问题,加入调试语句,调试情况如下:
void test(){ AVLtree<int, int> a; vector<int> Test = {4, 2, 6, 1, 3, 5, 15, 7, 16 ,14}; for (auto p : Test) { a.insert(p); cout << p << endl; a.Isblance(); cout << "-----------------" << endl; }}
可以看到,插入节点14的时侯出现问题,这是为什们那,我们只要把节点14插入的情况画出来既可:
我们可以看出,节点的br值没有更新正确。
在我们的此前的函数里,我们只是简单在旋转后把相关节点的br值变为0,这是有问题的,我们必须进行完善。
我们可以很容易把所有特殊情况推出:
图中的红节点并不是新插入节点,它只是我们这里逻辑上的child节点。
我们和双旋转的图对比一下,就可以发现,这个特殊情况就是child的一个子节点不为NULL。我们把所有情况列举出来,并且得出结果:
设c = child, b = father, a = grandfather
child的br:-1, father的br : 1, grandfather的br:-2
更新后为:child.br = 0, father.br = 0, grandfather.br = 1.
child的br:1, father的br : 1, grandfather的br:-2
更新后为:child.br = 0, father.br = -1, grandfather.br = 0.
child的br:-1, father的br : -1, grandfather的br:2
更新后为:child.br = 0, father.br = 1, grandfather.br = 0.
child的br:-1, father的br : 1, grandfather的br:2
更新后为:child.br = 0, father.br = 0, grandfather.br = -1.
完善后的调整函数为:
//当需要调整时调用adjust的重载函数。 void adjust(Node *father, Node *grandfather) { if (2 == grandfather->_br)//进行左旋转 { if (-1 == father->_br)//进行右左旋转 { Node *leftchild = father->_left; rotate_right_left(father); //调整相关节点的高度因子 if (0 == leftchild->_br) { leftchild->_br = father->_br = grandfather->_br = 0; } else if (1 == leftchild->_br) { leftchild->_br = 0; father->_br = 0; grandfather->_br = -1; } else { leftchild->_br = 0; father->_br = 1; grandfather->_br = 0; } } else { rotate_left(father); father->_br = grandfather->_br = 0; } } else if (-2 == grandfather->_br)//进行右旋转 { if (1 == father->_br)//进行左右旋转 { Node *leftchild = father->_right; rotate_left_right(father); //调整相关节点的高度因子 if (0 == leftchild->_br) { leftchild->_br = father->_br = grandfather->_br = 0; } else if (1 == leftchild->_br) { leftchild->_br = 0; father->_br = -1; grandfather->_br = 0; } else { leftchild->_br = 0; father->_br = 0; grandfather->_br = 1; } } else { rotate_right(father); father->_br = grandfather->_br = 0; } } }。
全部代码如下(只实现了插入操作):
#pragma once#include <iostream>#include <stack>#include <algorithm>using namespace std;//节点template<typename K, typename T = int>struct AVLNode{ typedef AVLNode<K, T> Node; AVLNode(const K& key, const T value = T()) :_key(key) ,_value(value) ,_br(0) ,_left(NULL) ,_right(NULL) ,_father(NULL) { } const K _key; T _value; int _br;(平衡因子) Node *_left; Node *_right; Node *_father;};//AVLTreetemplate<class K, class T = int>class AVLtree{public: typedef AVLtree<K, T> tree; typedef AVLNode<K, T> Node; AVLtree() :_root(NULL) {}; bool insert(const K& key, const T& value = T()) { Node *p = new Node(key, value); if (NULL == _root) { _root = p; return true; } Node *cur = _root; Node *father = cur; while (cur) { father = cur; if (key == cur->_key) return false; else if (key > cur->_key) cur = cur->_right; else cur = cur->_left; } if (father->_key > key) father->_left = p; else father->_right = p; p->_father = father; //每次插入完成后进行调整 adjust(p); return true; } void middle_display() { middle_display(_root); cout << endl; } bool Isblance() { int height = 0; return Isblance(_root, height); }protected: //左旋 void rotate_left(Node *father) { Node *grandfather = father->_father; Node *great_father = grandfather->_father; grandfather->_right = father->_left; if (father->_left != NULL) father->_left->_father = grandfather; father->_left = grandfather; grandfather->_father = father; if (NULL == great_father) { _root = father; } else { if (great_father->_left == grandfather) great_father->_left = father; else great_father->_right = father; } father->_father = great_father; } //右旋 void rotate_right(Node *father) { Node *grandfather = father->_father; Node *great_father = grandfather->_father; grandfather->_left = father->_right; if (father->_right != NULL) father->_right->_father = grandfather; father->_right = grandfather; grandfather->_father = father; if (NULL == great_father) { _root = father; _root->_father = NULL; } else { if (great_father->_left == grandfather) great_father->_left = father; else great_father->_right = father; } father->_father = great_father; } //左右旋 void rotate_left_right(Node *father) { father = father->_right; rotate_left(father); rotate_right(father); } //右左旋 void rotate_right_left(Node *father) { father = father->_left; rotate_right(father); rotate_left(father); } //调整函数 void adjust(Node *child) { Node *father = child->_father; while (child != _root) { if (father->_left == child) father->_br -= 1; else father->_br += 1; if (0 == father->_br) break; else if (1 == father->_br || -1 == father->_br) { child = father; father = father->_father; } else { adjust(child, father); break; } } } //adjust的重载函数 void adjust(Node *father, Node *grandfather) { if (2 == grandfather->_br)//进行左旋转 { if (-1 == father->_br)//进行右左旋转 { Node *leftchild = father->_left; rotate_right_left(father); //调整相关节点的高度因子 if (0 == leftchild->_br) { leftchild->_br = father->_br = grandfather->_br = 0; } else if (1 == leftchild->_br) { leftchild->_br = 0; father->_br = 0; grandfather->_br = -1; } else { leftchild->_br = 0; father->_br = 1; grandfather->_br = 0; } } else { rotate_left(father); father->_br = grandfather->_br = 0; } } else if (-2 == grandfather->_br)//进行右旋转 { if (1 == father->_br)//进行左右旋转 { Node *leftchild = father->_right; rotate_left_right(father); //调整相关节点的高度因子 if (0 == leftchild->_br) { leftchild->_br = father->_br = grandfather->_br = 0; } else if (1 == leftchild->_br) { leftchild->_br = 0; father->_br = -1; grandfather->_br = 0; } else { leftchild->_br = 0; father->_br = 0; grandfather->_br = 1; } } else { rotate_right(father); father->_br = grandfather->_br = 0; } } } void Inorder(Node *root) { if (NULL == root) return; middle_display(root->_left); cout << root->_key << ends; Inorder(root->_right); } bool Isblance(Node *root, int& height) { if (NULL == root) { return true; height = 0; } int leftmax = 0; if (!Isblance(root->_left, leftmax)) return false; int rightmax = 0; if (!Isblance(root->_right, rightmax)) return false; if (root->_br != rightmax - leftmax) { cout << "don't blance" << ends; cout << root->_key << endl; } if (abs(rightmax - leftmax) >= 2) return false; height = (max(leftmax, rightmax)) + 1; return true; }private: Node *_root;};
AVL数虽然在很大程度上保持了平衡,但是它却太难理解,维护代价高。RBTree相比AVLTree则更为简单。
- 平衡搜索树:AVLTree的实现
- 平衡搜索树-AVLTree的简单实现
- 数据结构——平衡二叉搜索树(AvlTree)的实现
- 平衡搜索树之AVLTree
- 平衡搜索树—AVLTree
- AVLTree----平衡二叉搜索树
- AVLTree二叉平衡搜索树
- 【数据结构】AVLTree(高度平衡的二叉搜索树)
- AVLTree 二叉平衡树 实现
- 【数据结构】中的平衡搜索树-AVLTree
- 平衡搜索树——AVLTree
- 二叉平衡树avlTree和红黑树rbTree的java实现
- AVLTree - 二叉平衡树的实现之一(C++)
- AVLTree - 二叉平衡树的实现之二(C++)
- AVLTree - 二叉平衡树的实现之二(C++)
- AVLTree - 二叉平衡树的实现之一(C++)
- Java实现平衡二叉树(AVLTree)的构建
- 平衡二叉树(AVLTree)
- 完美解决 ListView偶尔爆出的异常:java.lang.IllegalStateException
- Group By的介绍
- 混淆与反编译
- HDU 5919 分块做法
- 12战舰(1)54(4)95(7)160(11)174(14)190(17)204(20)
- 平衡搜索树:AVLTree的实现
- springMVC+ajax进行登录验证
- 24战舰(2)69(5)107(8)170(13)185(16)200(19)212(22)
- MySQL Show命令
- 浅析java集合框架
- MYSQL的基本Command
- MySQL Workbench 停止工作
- Flex 布局教程:语法篇
- Atiti attilax主要成果与解决方案与案例rsm版