您的位置:首页 > 其它

AVL(高度平衡的二叉树)

2017-07-10 20:11 357 查看
AVL叫做高度平衡的二叉树,以前老记不住这个名字,现在懂了,AVL它是在BST(平衡的二叉树中衍生过来的),因为BST树可能会出现在高度上规则差距很大的树,毕竟他的规则只是比根结点大的作为根结点的右结点,比根结点小的作为根结点的左树;他在BST树的基础上又增加了一条规则,左右子树在高度上最大的高度差只能是1,所以叫他是高度上平衡的排序树;

以下是AVL树的实现:

#pragma once

#include<iostream>
#include<stack>
using namespace std;

template<class Type>
class AVL;

template<class Type>
class AVLNode
{
friend class AVL<Type>;
public:
AVLNode():data(Type()),leftChild(NULL),rightChild(NULL),bf(0)
{}
AVLNode(Type d,AVLNode<Type> *left=NULL,AVLNode<Type>*rigth=NULL)
:data(d),leftChild(left),rightChild(rigth),bf(0)
{}
~AVLNode()
{}
private:
Type data;
AVLNode *leftChild;
AVLNode *rightChild;
int bf;
};
template<class Type>
class AVL
{
public:
AVL() : root(NULL)
{}
~AVL()
{}
public:
bool Insert(const Type &x)
{
return Insert(root, x);
}
bool Remove(const Type &x)
{
return Remove(root, x);
}
protected:
bool Insert(AVLNode<Type>*&t, const Type &x);
void RotateR(AVLNode<Type> *&ptr);
void RotateL(AVLNode<Type> *&ptr);
void RotateRL(AVLNode<Type> *&ptr);
void RotateLR(AVLNode<Type> *&ptr);
private:
AVLNode<Type> *root;
};


(1)插入函数Insert函数:

template<class Type>
bool AVL<Type>::Insert(AVLNode<Type>*&t, const Type &x)
{
///////////////////////////////////////////////////////////
这一部分使用非递归的做法实现BST的插入;这里用到了栈,是因为你每次插入一个节点以后都要修改他的父结点的平衡因子,
并且修改第一个父节点的平衡因子之后再修改他的父父结点的平衡因子,用一个栈有利于记录这个结点插入的时候走过的路径,那么在回溯的时候也就方便了;
stack<AVLNode<Type>*> st;
AVLNode<Type> *p = t;
AVLNode<Type> *pr = NULL;
while(p != NULL)
{
if(x == p->data)
return false;
pr = p;
st.push(pr);
if(x < p->data)
p = p->leftChild;
else
p = p->rightChild;
}
p = new AVLNode<Type>(x);
if(pr == NULL)//这是刚插入根结点的情况;
{
t = p;
return true;
}
if(x < pr->data)
pr->leftChild = p;
else
pr->rightChild = p;
到此位置,新插入的结点已经与之前的结点建立了联系,插入到他该插入的地方;接下来就要看新结点的插入对他的父节点的平衡因子有何影响;

///////////////////////////////////////////////////////////////////
while(!st.empty())
{
pr = st.top();
st.pop();
if(p == pr->leftChild)
pr->bf--;
else
pr->bf++;
if(pr->bf == 0)
break;
if(pr->bf==-1 || pr->bf==1)//倒回去继续查看父结点的平很因子;
{
p = pr;
}
else
{
///到这一步那肯定就不平衡了,需要调整平衡因子
if(pr->bf < 0)
{
if(p->bf < 0)
{
cout<<"RotateR"<<endl;
RotateR(pr);

}
else
{
cout<<"RotateLR(pr)"<<endl;
RotateLR(pr);

}
}
else
{
if(p->bf > 0)
{
cout<<"RotateL"<<endl;
RotateL(pr);

}
else
{
cout<<"RotateRL"<<endl;
RotateRL(pr);
}
}
break;//调整完以后一定要直接break;
}
}
到此位置,不平衡的结点已经调整过来了,但是以root为根结点的二插树的内部已经发生了变换,所以下面就是要将修改好的而插入与他的之前的父节点建立连接;
///////////////////////////////////////////////////////////////////
//目的是把调整过了平衡因子的结点和之前的结点关联起来;
if(st.empty())
{
//如果栈空了,说明他就是根结点
t = pr;
}
else
{
//否则把栈顶元素弹出来,将其连接起来;
AVLNode<Type> *q = st.top();//它是原来的父节点
if(pr->data < q->data)
q->leftChild = pr;
else
q->rightChild = pr;

}
return true;
}
旋转函数的我觉得简单的方法就是把旋转后的结果写出来,然后在将原来的结点做出相应的调整,并且一定要记得调整平衡因子;
template<class Type>
void AVL<Type>::RotateR(AVLNode<Type> *&ptr)
{
AVLNode<Type> *subR = ptr;
ptr = ptr->leftChild;
//ptr->rightChild = sub->leftChild ;//造成sub的leftChild有俩个了;
subR->leftChild = ptr->rightChild;
ptr->rightChild = subR;
ptr->bf = subR->bf = 0;
}

template<class Type>
void AVL<Type>::RotateL(AVLNode<Type> *&ptr)
{
AVLNode<Type> *subL = ptr;
ptr = ptr->rightChild;
subL->rightChild = ptr->leftChild;
ptr->leftChild = subL;
ptr->bf = subL->bf = 0;
}
template<class Type>
void AVL<Type>::RotateLR(AVLNode<Type> *&ptr)
{
AVLNode<Type> *subL = ptr->leftChild;
AVLNode<Type> *subR = ptr;	ptr = subL->rightChild;
subL->rightChild = ptr->leftChild;
ptr->leftChild = subL;
// ptr的平衡因子没有改
if(ptr->bf <= 0)
subL->bf = 0;
else
subL->bf = -1;

subR->leftChild = ptr->rightChild;
ptr->rightChild = subR;

if(ptr->bf == -1)
subR->bf = 1;
else
subR->bf = 0;
ptr->bf = 0;
}
template<class Type>//一定是从当前不平衡结点初开始旋转;
void AVL<Type>::RotateRL(AVLNode<Type> *&ptr)
{
AVLNode<Type> * subL = ptr;//ptr最终会成为左结点;
AVLNode<Type> * subR = ptr->rightChild ;//它会成为右节点;
ptr = subR->leftChild ;//最终的头结点
//以下是安排最终的左结点和最终的更结点之间附属结点之间的变化;画图更易理解
subL->rightChild = ptr->leftChild ;
ptr->leftChild = subL;
if(ptr->bf <= 0)
{
subL->bf = 0;
}
else
{
subL->bf = -1;
}
//以下安排最终的右结点和根结点他们的附属结点直接的变化,画图更易理解
subR->leftChild = ptr->rightChild ;
ptr->rightChild = subR;
if(ptr->bf <=0)
{
subR->bf = -1;//有问题;
}
else
{
subR->bf = 0;
}
ptr->bf = 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息