AVL树的基本实现

来源:互联网 发布:淘宝怎样开通直通车 编辑:程序博客网 时间:2024/05/22 12:24

       在学习二叉树后我们知道它存在缺陷,就是当我们插入一些有序节点时就基本退化为链表的形式,达不到我们想要的结果,因此,在这里为了解决这个问题就引出了平衡二叉树(AVL)的概念。

AVL树又称为高度平衡的二叉搜索树,它能保持二叉树的高度平衡,尽量降低二叉树的高度,减少树的平均搜索长度,那它具有哪些性质呢?

1.左右子树的高度差的绝对值不超过1;

2.树中的每个左子树和右子树都是AVL树;

3. 每个节点都有一个平衡因子(balance factor--bf),任一节点的平衡因子是-1,0,1。(每个节点的平衡因子等于右子树的高度减去左子树的高度 ).

提到平衡因子只有-1,1,0这几种限制,就引来了旋转问题,旋转的目的是什么呢?它在于在某种情况下将其高度降下来,从而满足AVL的性质特点。

旋转一般分为四种情况:

1.左单旋;

2.右单旋.(原理类似)





3.左右双旋;

4.右左双旋.

这两种当然可以直接调用上面的两种单旋方式,顾名思义,左右双旋是先调用左单旋再右单旋;右左双旋是先调用右单旋再左单旋。但是这两种双旋不能只是单单的调用单旋就能解决的,在某种特殊的情况下,调用单旋后将平衡因子都改为0是不对的,具体看如下图分析:




分析就到这,下来是插入节点的代码:

template<class K,class V>bool AVLTree<K,V>::Insert(const K& key,const V& value){//以key值为标准,key值相同插入不成功if (_root==NULL){_root=new Node(key,value);return true;}Node* cur=_root;Node* parent=NULL;while(cur){if (cur->_key < key){parent=cur;cur=cur->_right;}else if (cur->_key > key){parent=cur;cur=cur->_left;}else return false;}//找到插入位置cur,与parent连接上cur=new Node(key,value);if (parent->_key < key){parent->_right=cur;cur->_parent=parent;}else if (parent->_key > key){parent->_left=cur;cur->_parent=parent;}//检查是否平衡,不平衡进行调整parent=cur->_parent;while (parent){//先判断cur添加的位置,从而确定怎样更改parent->_bfif (parent->_left==cur){parent->_bf--;}if (parent->_right==cur){parent->_bf++;}if (parent->_bf==0){break;}else if (parent->_bf==1 || parent->_bf==-1) //树的高度变了,继续往上调整{                                      cur=parent;parent=cur->_parent;}else   //parent->_bf==2 || parent->_bf==-2{if (parent->_bf==2){if (cur->_bf==1)  //需要左单旋_RotateL(parent);else_RotateRL(parent); //右左双旋}else if (parent->_bf==-2){if (parent->_bf==-2){if (cur->_bf==-1)  //需要右单旋_RotateR(parent);else_RotateLR(parent); //左右双旋}}}}}

下来是四种旋转的实现:

template<class K,class V>void AVLTree<K,V>::_RotateL(Node*& parent){Node* subR=parent->_right;Node* subRL=subR->_left;Node* ppNode=parent->_parent;subR->_left=parent;parent->_right=subRL;if(subRL)subRL->_parent=parent;parent->_parent=subR;if (ppNode==NULL){_root=subR;subR->_parent=NULL;}else{if (ppNode->_right==parent)ppNode->_right=subR;elseppNode->_left=subR;subR->_parent=ppNode;}subR->_bf=parent->_bf=0;     //更新平衡因子}template<class K,class V>void AVLTree<K,V>::_RotateR(Node*& parent){Node* subL=parent->_left;Node* subLR=subL->_right;Node* ppNode=parent->_parent;parent->_left=subLR;if (subLR){subLR->_parent=parent;}subL->_right=parent;parent->_parent=subL;if (ppNode==NULL){_root=subL;subL->_parent=NULL;}else{if (ppNode->_left==parent)ppNode->_left=subL;elseppNode->_right=subL;        subL->_parent=ppNode;}subL->_bf=parent->_bf=0;}template<class K,class V>void AVLTree<K,V>::_RotateLR(Node*& parent){Node* subL=parent->_left;Node* subLR=subL->_right;int bf=subLR->_bf;_RotateL(parent->_left);_RotateR(parent);if (bf==0)  //新增节点{parent->_bf=subL->_bf=subLR->_bf=0;}else if(bf==-1)  //b处插入{  parent->_bf=1;subL->_bf=0;subLR->_bf=0;}else           //c处插入{parent->_bf=0;subL->_bf=-1;subLR->_bf=1;}}template<class K,class V>void AVLTree<K,V>::_RotateRL(Node*& parent){Node* subR=parent->_right;Node* subRL=subR->_left;int bf=subRL->_bf;_RotateR(parent->_right);_RotateL(parent);if (bf==0)  //新增节点{parent->_bf=subR->_bf=subRL->_bf=0;}else if(bf==-1)  //b处插入{  parent->_bf=0;    subR->_bf=1;subRL->_bf=0;}else           //c处插入{parent->_bf=-1;subR->_bf=0;subRL->_bf=1;}}

在AVL树中还有个问题很重要,就是如何判断其是否满足高度平衡的条件?

首先,是否平衡是由平衡因子决定的,而平衡因子的求解是:右子树高度-左子树高度;所以我们必须将左右子树的高度求解出来,看如下代码:

template<class K,class V>bool AVLTree<K,V>::_Isbalance(Node* root){if (root==NULL)return true;size_t LeftHeight=_Height(root->_left);size_t RightHeight=_Height(root->_right);int bf=RightHeight-LeftHeight;if (root->_bf!=bf){cout<<"Unbalance:"<<root->_key<<endl;return false;}return abs(bf)<2 && _Isbalance(root->_left) && _Isbalance(root->_right);}


这种方法可以是可以,但是每次都要将当前节点的左右子树高度求出来,时间复杂度是相对较高的,最坏情况下为O(N^2).那么该如何优化呢?

刚才我们提到,每次都得将当前节点的左右子树高度求出来,那么我们是不是可以在判断该节点的同时将其高度返回去,这样遍历一次就可以了,时间复杂度自然就降为O(n).

思路:采取后序遍历的方式,先判断左节点,合法则高度加1,然后往上一层递归返回,再进行右节点的计算,最后再进行根节点的计算。在后序遍历中,通过传递引用的方式将子树的高度传到根节点处去。


template<class K,class V>bool AVLTree<K,V>::_IsbalanceOP(Node* root,size_t& Height){if (root==NULL){Height=0;return true;}size_t LeftHeight=0;size_t RightHeight=0;if (_IsbalanceOP(root->_left,LeftHeight)==false)return false;if(_IsbalanceOP(root->_right,RightHeight)==false)return false;//表示以当前节点为根节点的左右子树是平衡的int bf=RightHeight-LeftHeight;if (abs(bf)<2){Height=1+(RightHeight > LeftHeight ? RightHeight : LeftHeight);return true;}}


我将完整代码托管到github上:AVLTree


0 0
原创粉丝点击