平衡搜索树(一) AVL树
AVL树
AVL树又称为高度平衡的二叉搜索树,是1962年有俄罗斯的数学家G.M.Adel'son-Vel'skii和E.M.Landis提出来的。它能保持二叉树的高度 平衡,尽量降低二叉树的高度,减少树的平均搜索长度AVL树的性质
1. 左子树和右子树的高度之差的绝对值不超过1
2. 树中的每个左子树和右子树都是AVL树
3. 每个节点都有一个平衡因子(balance factor--bf),任一节点的平衡因子是-1,0,1。(每个节点的平衡因子等于右子树的高度减去左子 树的高度 )
AVL树的效率
一棵AVL树有N个节点,其高度可以保持在log2N,插入/删除/查找的时间复杂度也是log2N。
当出现不平衡的情况时的四种情况:
1.只需要右旋(汉子笔画为一“撇”),无论在黄(son)的左边插入还是右边插入,红(grandparent)的平衡因子,绿(parent)的平衡因子总能保持为0;
2.只需要左旋(汉子笔画为一“捺”)与情况1类似,此处就不再累赘;
3.左右旋(汉字笔画为一“撇”,一“捺”)
(1)绿的平衡因子为 0。有且只有一种可能;
(2)绿的平衡因子为-1。在绿(son)的左边插入,红(grandparent)的平衡因子为1,黄(parent)的平衡因子为0,绿(son)的平衡因子为0;
(3)绿的平衡因子为1。在绿(son)的右边插入,红(grandparent)的平衡因子为0,黄(parent)的平衡因子为-1,绿(son)的平衡因子为0;
4.右左旋(汉字笔画为一“捺”,一“撇”),情况与左右旋类似;
Now 图画完了~~ 大体思想了解了 闲话就不多叙述了--直接上代码
//AVLTree 的节点类
1 template<class K,class V> 2 struct AVLTreeNode 3 { 4 typedef AVLTreeNode<K, V> Node; 5 AVLTreeNode(const K& key, const V& value) 6 :_left(NULL), _right(NULL), _parent(NULL) 7 , _balance(0), _key(key), _value(value) 8 {} 9 10 Node * _left; 11 Node * _right; 12 Node * _parent; 13 int _balance; 14 K _key; 15 V _value; 16 };
//AVLTree (这个就是AVLTree 的类)
1 template<class K,class V> 2 class AVLTree 3 { 4 typedef AVLTreeNode<K, V> Node; 5 public: 6 AVLTree() 7 :_root(NULL) 8 {} 9 public: 10 //增加节点 11 bool _Push(const K& key, const V& value); 12 void _LeftSpin(Node *& parent); 13 void _RightSpin(Node * & parent); 14 void _LeftRightSpin(Node *& _RightSpinparent); 15 void _RightLeftSpin(Node *& parent); 16 17 //查找结点 18 Node* _Find(const K& key); 19 20 //修改节点 21 bool _Change(const K& key,const V& value); 22 23 //检测 24 void _LevelOrder(); 25 void _InOrder(){ InOrder(_root); } 26 int _Depth(){ Depth(_root); } 27 void InOrder(Node * root); 28 int Depth(Node * root); 29 protected: 30 Node * _root; 31 };
//AVLTree的构建
1 //增加节点 2 template<class K,class V> 3 bool AVLTree<K, V>::_Push(const K& key, const V& value) 4 { 5 if (_root == NULL) 6 { 7 _root = new Node(key, value); 8 return true; 9 } 10 else //如果要根节点不为空 11 { 12 Node * insert = new Node(key, value); 13 Node * cur = _root; 14 Node * parent = NULL; 15 while (cur) //找插入的位置 16 { 17 parent = cur; 18 if (key > cur->_key) 19 { 20 cur = cur->_right; 21 } 22 else if (key < cur->_key) 23 { 24 cur = cur->_left; 25 } 26 else 27 { 28 return false; 29 } 30 } 31 if (key > parent->_key) //将该节点插入到parent的右边 32 { 33 parent->_right = insert; 34 insert->_parent = parent; 35 } 36 else //将该节点插入到parent的左边 37 { 38 parent->_left = insert; 39 insert->_parent = parent; 40 } 41 cur = insert; //cur指向新插入的节点
42 while (parent) //向上调节平衡因子 43 { 44 if (cur->_key > parent->_key) 45 { 46 parent->_balance++; 47 } 48 else 49 { 50 parent->_balance--; 51 } 52 if (parent->_balance == 0 || parent->_balance == 2 || parent->_balance == -2) //当_balance == 0 说明已经平衡了。_balance == 2 || _balance == -2 说明需要调整了
53 { 54 break; 55 } 56 cur = parent; 57 parent = cur->_parent; 58 } 59 60 if (parent && (parent->_balance == 2 || parent->_balance == -2)) //如果_balance == 2 || _balance == -2 61 { 62 if (parent->_balance == 2) 63 { 64 if (cur->_balance == 1) 65 { 66 _LeftSpin(parent); //上面的情况2 67 } 68 else 69 { 70 _RightLeftSpin(parent); //上面的情况472 } 73 } 74 else if(parent->_balance == -2) 75 { 76 if (cur->_balance == -1) 77 { 78 _RightSpin(parent); //上面的情况1
79 } 80 else 81 { 82 _LeftRightSpin(parent); //上面的情况384 } 85 } 87 } 88 return true; 89 } 90 }
//左旋(按照上面的来敲带码,其实是很简单滴)
1 template<class K, class V> 2 void AVLTree<K, V>::_LeftSpin(Node *& parent) 3 { 4 Node* son = parent->_right; 5 Node* grandparent = parent->_parent; 6 7 parent->_right = son->_left; 8 if (son->_left) 9 { 10 son->_left->_parent = parent; 11 } 12 son->_left = parent; 13 parent->_parent = son; 14 15 son->_parent = grandparent; 16 if (grandparent) 17 { 18 if (parent->_key > grandparent->_key) 19 { 20 grandparent->_right = son; 21 } 22 else 23 { 24 grandparent->_left = son;
25 } 26 } 27 28 parent->_balance = 0; //将平衡因子置为零 29 son->_balance = 0; 30 31 if (_root == parent) 32 { 33 _root = son; 34 } 35 parent = son; 36 }
//左右旋
template<class K, class V> void AVLTree<K, V>::_LeftRightSpin(Node *& parent)
{ Node * son = parent->_left; bool left = false; bool right = false; if (son->_right->_balance == -1) //如图,如果son 的 balance == -1 调整好后 grandparent 的 平衡因子为 1;即 (当前parent->right == 1);
{ left = true; } else if (son->_right->_balance == 1) //如图,如果 son 的 balance == 1 调整好后 parent 的 平衡因子为 -1;即(当前parent->left == -1); { right = true; } _LeftSpin(son); //(这里有一个坑:参数传的是引用,所以实参不能传(grandparent->_left)否则就会有神奇的事情发生^_^ ~~ 这里要小心再小心!!!前车之鉴呀大兄弟)
_RightSpin(parent); if (left) { parent->_right->_balance = 1; } else if (right) { parent->_left->_balance = -1; } }