您的位置:首页 > 其它

AVL树的插入删除操作

2017-07-23 11:32 363 查看
//.......................avl.h
#pragma once

#include<iostream>
#include<stack>
using namespace std;
//................................动态平衡树-----AVL树
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>*right=NULL)
:data(d),leftChild(left),rightChild(right),bf(0)
{}
~AVLNode()
{}
private:
Type data;
AVLNode *leftChild;
AVLNode *rightChild;
int bf;
};

//AVL类
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>*&rt,const Type &x);
bool Remove(AVLNode<Type>*&t,const Type &x);
AVLNode<Type>* RotateR(AVLNode<Type> *&ptr);
AVLNode<Type>* RotateL(AVLNode<Type> *&ptr);
AVLNode<Type>* RotateRL(AVLNode<Type> *&ptr);
AVLNode<Type>* RotateLR(AVLNode<Type> *&ptr);
private:
AVLNode<Type> *root;
};

/*
8  --k1                     5
5   --k2  ---- 经过右旋转  2   8
2 7                            7
*/

template<class Type>
AVLNode<Type>* AVL<Type>::RotateR (AVLNode<Type>*&ptr)
{

AVLNode<Type> *k1=ptr;
ptr=k1->leftChild;
k1->leftChild=ptr->rightChild;
ptr->rightChild=k1;
k1->bf=ptr->bf=0;
return ptr;
}

/*
5   --k1                   8
8  --k2  ---左旋转     5   10
7  10                      7
*/

template<class Type>
AVLNode<Type>* AVL<Type>::RotateL(AVLNode<Type>*&ptr)
{
AVLNode<Type> *k1=ptr;
ptr=k1->rightChild;
k1->rightChild=ptr->leftChild;
ptr->leftChild=k1;
k1->bf=ptr->bf=0;
return ptr;
}

/*
//..........................RL
18              18                20
14      22  ---> 14     20  --->   18    22
20    24              22    14  19    24
19                    19    24
18不平衡,先对20 22做一次右单旋转,再对18 20做一次左单旋转
*/

template<class Type>
AVLNode<Type>* AVL<Type>::RotateRL(AVLNode<Type>*&ptr)
{
AVLNode
4000
<Type>*subL = ptr;
AVLNode<Type> *subR = ptr->rightChild ;
ptr = subR->leftChild ;
//第一次单旋转
subR->leftChild = ptr->rightChild ;
ptr->rightChild = subR;
if(ptr->bf >= 0)
subR->bf = 0;
else
subR->bf = 1;
//第二次单旋转
subL->rightChild = ptr->leftChild ;
ptr->leftChild = subL;
if(ptr->bf <= 0)
subL->bf = 0;
else
subL->bf = -1;

ptr->bf = 0;
return ptr;
}

/*
//.............LR
18              18              16
14     20  ---> 16     20  ---->14     18
12  16          14            12   15       20
15          12  15
18 不平衡  18 14 16 需要双旋转,先对14 16做一次单旋转(左旋转),再对16 18做一次单旋转(右旋转)
*/
template<class Type>
AVLNode<Type>* AVL<Type>::RotateLR(AVLNode<Type>*&ptr)  //双旋转 先左后右
{
AVLNode<Type> *subR=ptr;
AVLNode<Type> *subL=ptr->leftChild ;
ptr=subL->rightChild ;
//第一次单旋转
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 =0;
else
subR->bf =1;

ptr->bf =0;  //根的平衡因子一定为0
return ptr;
}

//删除操作:两个过程:删除操作以及调节二叉树平衡
/*
1.删除的节点最多只有一个子女结点
2.删除的节点有左右子树,此时需要考虑父节点的平衡因子,若为1或-1,则不需要调整,
若bf = 0,此时t=pr,向上回溯,若为2或者-2,需要进行旋转调整平衡,此时需要根据父节点的平衡因子来决定如何旋转。
*/
template<class Type>
bool AVL<Type>::Remove (AVLNode<Type> *&t,const Type &x)
{
if(t == NULL)
return false;
AVLNode<Type> *p = t;
AVLNode<Type> *q;
AVLNode<Type> *pr = NULL;
stack<AVLNode<Type> *> st;
while(p != NULL)
{
if(p->data == x)
break;

pr = p; //父节点等于p
st.push(pr);

if(x< p->data)
p = p->leftChild;
else
p = p->rightChild;
}

if(p == NULL)  //未找到被删结点,删除失败
return false;
//被删结点有两个子女
if(p->leftChild!=NULL && p->rightChild!=NULL)
{
pr = p;
st.push(pr);

q = p->leftChild;  //pr是q的父节点
while(q->rightChild != NULL)
{
pr = q;
q = q->rightChild;
}
p->data = q->data; //用q的值填补p
p = q; //被删结点转化为q
}

//被删节点p只有一个子女结点
if(p->leftChild != NULL)
q = p->leftChild;
else
q = p->rightChild;

if(pr == NULL)  //删除的是根节点
t = q;  //根节点变为q
else
{
if(pr->leftChild == p)
pr->leftChild = q;
else
pr->rightChild = q;

///////////////////////////////////
while(!st.empty())
{
pr = st.top();
st.pop();

if(pr->leftChild == q)
pr->bf++;
else
pr->bf--;

if(pr->bf==1 || pr->bf==-1)
break;
else if(pr->bf == 0)
q = pr;
else
{
if(pr->bf > 0)
q = pr->rightChild;
else
q = pr->leftChild;

if(q->bf == 0) // 单旋转
{
if(pr->bf > 0)
{
RotateL(pr);
pr->bf = -1;
pr->leftChild ->bf = 1;
}
else
{
RotateR(pr);
pr->bf = -1;
pr->rightChild ->bf = 1;
}
}
else if(q->bf > 0)
{
if(pr->bf > 0)   // \
{
RotateL(pr);
}
else            //   <
{
RotateLR(pr);
}
}
else
{
if(pr->bf < 0)   //     /
{
RotateR(pr);
}
else            //      >
{
RotateRL(pr);
}
}

break;
}
}

AVLNode<Type> *ppr = st.top();

cf2b
if(ppr->data > pr->data )
ppr->leftChild = pr;
else
ppr->rightChild = pr;

}
delete p;
return true;
}

//Insert:两个过程:插入数据以及调节平衡
template<class Type>
bool AVL<Type>::Insert(AVLNode<Type>*&rt, const Type &x)
{
AVLNode<Type> *pr = NULL;
AVLNode<Type> *t = rt;  //使p指向根节点
stack<AVLNode<Type>*> st;

while(t != NULL)    //当节点不为空时
{
if(x == t->data )
return false;
pr = t;
st.push(pr);  //将父节点压栈
if(x < t->data)  //如果x小于节点的值,就在节点的左子树中插入x   根据二叉排序树进行插入
t= t->leftChild ;
else
t = t->rightChild;  //否则,就在节点的右子树中插入x
}
t= new AVLNode<Type>(x);  //如果节点为空,就在此节点处加入x信息
if(rt == NULL)   //如果父节点为空,即是颗空树
{
rt = t;  //为根结点
return true;
}
if(x < pr->data) //父节点的左树插入
pr->leftChild = t;
else
pr->rightChild = t;

//当栈不平衡时,调整平衡因子
while(!st.empty())  //当栈不空时
{
pr = st.top();
st.pop();  //重新出到父节点
if(t == pr->leftChild)
pr->bf--;  //左树,平衡因子-1
else
pr->bf++;
if(pr->bf == 0)  //判断父节点的平衡因子
break;  //已经平衡 不用再调
else if(pr->bf==-1 || pr->bf==1)
{
t = pr;  //父节点向上追踪
}
else  //不平衡
{
if(pr->bf < 0)  // 父节点的平衡因子小于0  左树高
{
if(t->bf < 0)  //    /  还需要判断子节点的平衡因子
{
RotateR(pr);
}
else       //  <
{
RotateLR(pr);
}
}
else
{
if(t->bf > 0)   //  \
{
RotateL(pr);
}
else         //  >
{
RotateRL(pr);
}
}
break;
}
}
if(st.empty())  //如果栈不空,
{
rt=pr;
}
else
{
AVLNode<Type> *s = st.top();  //q指向栈顶
if(pr->data <s->data)
s->leftChild =pr;
else
s->rightChild =pr;

}
return true;
}

//........................test.cpp

#include"avl.h"
void main()
{
int ar[] = {16,3,7,11,9,26,18,14,15};
int n = sizeof(ar) / sizeof(int);
AVL<int> avl;
for(int i=0; i<n; ++i)
{
avl.Insert(ar[i]);
}
avl.Remove(1);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息