1.什么是AVL树
AVL树又称为高度平衡的二叉搜索树,它能保持二叉树的高度平衡,尽量降低二叉树的高度,减少树的平均搜索长度(近似完全二叉树)。
2.为什么叫AVL树呢?
应该是因为它是由俄罗斯数学家G.M.Adel'son-Vel'skii和E.M.Landis在1962年提出来的,所以以他们的名字命名了平衡搜索树。^*^
3.AVL树的性质:
(1)左子树和右子树的高度之差的绝对值不超过1;
(2)树中的每个左子树、右子树都是AVL树;
(3)每个节点都有一个平衡因子(balance factor-bf),任意节点的平衡因子是-1、0、1。(每个节点的平衡因子等于右子树的高度减去左子树的高度)
4.AVL树的效率:
查找、插入和删除在平均和最坏情况下的时间复杂度都是log以2为底n的对数。
5.代码实现AVL树:
#pragma once #include<iostream> using namespace std; #include<math.h> template<class K, class V> struct AVLTreeNode { AVLTreeNode* _left; AVLTreeNode* _right; AVLTreeNode* _parent; K _key; V _value; int _bf; // 平衡因子 AVLTreeNode(const K& key,const V& value) :_left(NULL) , _right(NULL) , _parent(NULL) , _key(key) , _value(value) , _bf(0) {} }; 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; } Node* parent = NULL; Node* cur = _root; //寻找插入位置 while (cur) { if (cur->_key > key) { parent = cur; cur = cur->_left; } else if (cur->_key < key) { parent = cur; cur = cur->_right; } else { return false; } } //在找到的位置插入 cur = new Node(key, value); if (parent->_key > key) { parent->_left = cur; } else { parent->_right = cur; } cur->_parent = parent; //插入后 更新平衡因子:插入一个结点后,它的父亲结点平衡因子变为0,则不继续向上更新;如果父亲结点的 平衡因子变为1或-1,需要一直向上更新,直到父亲结点为空;如果父亲结点的平衡因子是2,就需要旋转 if (cur == parent->_left) parent->_bf--; else ++ parent->_bf; while (parent) { if (parent->_bf == 0) { return true; } else if (parent->_bf == 1 || parent->_bf == -1) { Node* gradparent = parent->_parent; if (gradparent) { if (parent == gradparent->_left) --gradparent->_bf; else ++gradparent->_bf; } parent = parent->_parent; } else { if (parent->_bf == 2) { if (parent->_right->_bf == 1) RotateL(parent); else RotateRL(parent); } else if (parent->_bf == -2) { if (parent->_left->_bf == -1) RotateR(parent); else RotateLR(parent); } break; } } return true; } //左右单旋的时候也要调平衡因子,以下面的测试代码为例,在插入9后,需要右单旋。一开始旋转成功了,但是代码还是有误,最后 发现平衡因子出现问题,改了平衡因子就对了。同理插入26后也需要在左单旋处改平衡因子,如下图所示。 void RotateR(Node* parent)//右单旋 { Node* subL = parent->_left; Node* subLR = subL->_right; parent->_left = subLR; if (subLR != NULL) subLR->_parent = parent; parent->_bf = 0; Node* gradparent = parent->_parent; subL->_right = parent; parent->_parent = subL; subL->_bf = 0; if (gradparent == NULL) { _root = subL; subL->_parent = NULL; } else { if (gradparent->_left == parent) { gradparent->_left = subL; } else { gradparent->_right = subL; } subL->_parent = gradparent; } } void RotateL(Node* parent)//左单旋 { Node* subR = parent->_right; Node* subRL = subR->_left; parent->_right = subRL; if (subRL) subRL->_parent = parent; parent->_bf = 0; Node* gradparent = parent->_parent; subR->_left = parent; parent->_parent = subR; subR->_bf = 0; if (gradparent == NULL) { _root = subR; subR->_parent = NULL; } else { if (gradparent->_left == parent) gradparent->_left = subR; else gradparent->_right = subR; subR->_parent = gradparent; } } void RotateLR(Node* parent)//先左后右双旋 { Node* subL = parent->_left; Node* subLR = subL->_right; int bf = subLR->_bf; RotateL(parent->_left); RotateR(parent); if (bf == -1) { subL->_bf = 0; parent->_bf = 1; subLR->_bf = 0; } else if (bf == 1) { subL->_bf = -1; parent->_bf = 0; subLR->_bf = 0; } else subL->_bf = parent->_bf = subLR->_bf = 0; } void RotateRL(Node* parent)//先右后左双旋 { Node* subR = parent->_right; Node* subRL = subR->_left; int bf = subRL->_bf; RotateR(parent->_right); RotateL(parent); if (bf == -1) { subR->_bf = 1; parent->_bf = 0; subRL->_bf = 0; } else if (bf == 1) { subR->_bf = 0; parent->_bf = -1; subRL->_bf = 0; } else { subR->_bf = parent->_bf = subRL->_bf = 0; } } void InOrder() { cout << "InOrder" << endl; _InOrder(_root); cout << endl; } bool IsBalance() { return _IsBalance(_root); } protected: void _InOrder(Node* root) { if (root == NULL) { return; } else { _InOrder(root->_left); cout << root->_key << " "; _InOrder(root->_right); } } //bool _IsBalance(Node* root,size_t height)//时间复杂度是O(n) //{ // if (root == NULL) // { // height = 0; // return true; // } // int LeftHeight = 0; // int RightHeight = 0; // if(_IsBalance(root->_left, LeftHeight) == false) // return false; // if(_IsBalance(root->_right, RightHeight) == false) // return false; // height = LeftHeight > RightHeight ? LeftHeight + 1 : RightHeight + 1; // return (abs(RightHeight - LeftHeight)) < 2; //} bool _IsBalance(Node* root)//判断是否平衡 { if (root == NULL) { return true; } int LeftHeight = Height(root->_left); int RightHeight = Height(root->_right); return (abs(LeftHeight - RightHeight) < 2) && _IsBalance(root->_left) && _IsBalance(root->_right); } int Height(Node* root) { if (root == NULL) return 0; int l = Height(root->_left); int r = Height(root->_right); return l > r ? l + 1 : r + 1; } private: Node* _root; };
测试代码: void TestAVLTree() { int a[] = { 16, 3, 7, 11, 9, 26, 18, 14, 15 }; AVLTree<int, int> t; //for (size_t i = 0; i < sizeof(a) / sizeof(a[0]); ++i) //{ // t.Insert(a[i], a[i]); //} t.Insert(16,0); t.Insert(3,0); t.Insert(7,0); t.Insert(11, 0); t.Insert(9, 0); t.Insert(26, 0); t.Insert(14, 0); t.Insert(18, 0);//这种插入方式方便查找错误,对于我这种菜鸟^o^ cout << t.IsBalance() << endl; t.InOrder(); }
注意:写代码时注意分清逻辑等于和赋值等于。
一图以16为父亲节点右单旋变二图,更新parent、subL的平衡因子_bf;三图以7为父亲节点左单旋变四图,也需要更新parent、subR的平衡因子_bf。
左右双旋,因为不确定子树的情况,可能为空,有一个结点,再或者连着高度为h的子树,因此不光要旋转还要更新平衡因子,可以根据图思考代码;右左双旋同理。