AVL平衡二叉树
Posted cqy-wt1124
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AVL平衡二叉树相关的知识,希望对你有一定的参考价值。
平衡二叉树
二叉树中所有结点的平衡因子BF
的绝对值均小于等于1
,即:(|BF|leq1)。平衡因子是,结点的左子树高度减去右子树的高度。平衡因子BF
绝对值大于1
表示二叉树失衡。
插入失衡
两种情况:
- 结点的平衡因子是
1
,向该结点的左子树插入结点,该结点的平衡因子变为2
,导致失衡; - 结点的平衡因子是
-1
,向该结点的右子树插入结点,该结点的平衡因子变为-2
,导致失衡。
如何解决失衡?
关键问题是要找到失衡结点,离插入结点最近的失衡结点。
失衡结点的特点:
- 一定是插入结点的祖父结点
- 插入结点时一定经过失衡结点
解决办法:
采用递归的方法进行插入,插入成功后会进行回代,因此在回代的过程中可以判断结点是否失衡,从而能够找到离插入结点最近的失衡结点。
/*
1、判断二叉树是否失衡,若失衡返回true,否则返回false
2、若二叉树失衡,则返回离插入结点最近的结点
*/
bool IsBalanced(BTNode<T> *&T,T key)
{
if(!T)
{
//未找到值为key的结点,进行插入
Insert(key);
return true;
}
else if(T->data==key)
{
return false;//找到结点key,不可插入
}
else if(T->data>key)
{
bool temp=IsBalanced(T->lchild,key);//如果temp为真,则表示结点插入到T的左子树
if(temp)
{
//判断T的平衡因子,若等于1,则需要调整
}
}
else
{
//同上
}
}
附上完整代码:
#include <iostream>
using namespace std;
//结点结构
template <class T>
class BTNode
{
public:
//结点数据
T data;
//左右孩子指针
BTNode<T> *lchild, *rchild;
//添加平衡因子
int BF;
public:
//构造函数
BTNode(T D, int bf = 0, BTNode<T> *l = NULL, BTNode<T> *r = NULL) : data(D), BF(bf), lchild(l), rchild(r) {}
};
//AVL平衡二叉树
template <class T>
class AVLTree
{
//私有属性
private:
//二叉树根节点
BTNode<T> *root;
private:
//销毁二叉树
void Destory(BTNode<T> *&rt)
{
if(rt)
{
this->Destory(rt->lchild);
this->Destory(rt->rchild);
delete rt;
}
}
//二叉树查找
//和二叉排序树的查找方法一样
bool SearchAVL(BTNode<T> *rt, T key, BTNode<T> *&p, BTNode<T> *f = NULL)
{
if (!rt) //查找失败,返回false
{
p = f; //p指向查找路径上最后访问的元素
return false;
}
else if (rt->data == key) //查找成功,返回true
{
p = rt; //p指向查找到的元素
return true;
}
else if (rt->data > key)
{
return this->SearchAVL(rt->lchild, key, p, rt);
}
else
{
return this->SearchAVL(rt->rchild, key, p, rt);
}
}
//左旋处理
void L_Rotate(BTNode<T> *&p)
{
BTNode<T> *R = p->rchild; //R指向p的左孩子
p->rchild = R->lchild; //p的右孩子指向R的左孩子
R->lchild = p; //R的左孩子指向p
p = R; //该二叉树的根节点变为R
}
//右旋处理
void R_Rotate(BTNode<T> *&p)
{
BTNode<T> *L = p->lchild;
p->lchild = L->rchild;
L->rchild = p;
p = L;
}
//左平衡处理,已知结点的平衡因子是+2,因此必定是在该结点的左子树插入的结点
//二叉排序树的根节点平衡因子的绝对值大于1,需进行平衡处理
void LeftBalance(BTNode<T> *&p)
{
BTNode<T> *L = p->lchild; //L指向p的左孩子
/*
判断L的平衡因子
若平衡因子为1,表示新节点插入在L的左子树
若平衡因子为-1,表示新节点插入在L的右子树
*/
switch (L->BF)
{
case 1: //结点插入在L的左子树,需进行右旋处理
this->R_Rotate(p);
p->BF = 0;
p->rchild->BF = 0; //右旋处理后,需改变旋转结点的平衡因子
break;
case -1:
{ //结点插入在L的右子树,需进行双旋处理
BTNode<T> *L_R = L->rchild;
switch (L_R->BF)
{
case 1: //结点插入在L_R的左子树
p->BF = -1;
L->BF = 0;
break;
case 0: //结点L_R就是新插入的结点
p->BF = 0;
L->BF = 0;
break;
case -1: //结点插入在L_R的右子树
p->BF = 0;
L->BF = 1;
break;
}
L_R->BF = 0;
this->L_Rotate(L); //先左旋处理
this->R_Rotate(p); //后右旋处理
break;
}
}
}
//右平衡处理,已知结点的平衡因子是-2,因此必定是在该结点的右子树插入的结点
void RightBalance(BTNode<T> *&p)
{
BTNode<T> *R = p->rchild;
switch (R->BF)
{
case 1:
{ //新节点插入在R的左子树上,需进行双旋处理
BTNode<T> *R_L = R->lchild;
switch (R_L->BF)
{
case 1: //结点插入在R_L的左子树上
p->BF = 0;
R->BF = -1;
break;
case 0: //R_L就是新插入的结点
p->BF = 0;
R->BF = 0;
break;
case -1: //结点插入在R_L的右子树上
p->BF = 1;
R->BF = 0;
break;
}
R_L->BF = 0;
this->R_Rotate(R); //先右旋处理
this->L_Rotate(p); //后左旋处理
break;
}
case -1: //新节点插入在R的右子树上,需进行左旋处理
p->BF = 0;
R->BF = 0;
this->L_Rotate(p);
break;
}
}
//向二叉树中插入结点,并保持平衡
bool InsertAVL(BTNode<T> *&rt, T key, bool &taller) //taller用来记录二叉树是否长高
{
if (!rt) //表示未在二叉树中找到结点值为key的结点,需插入结点
{
rt = new BTNode<T>(key, 0, NULL, NULL); //将新节点赋值给rt指针
taller = true;
return true;
}
else if (rt->data == key) //存在key,返回false
{
taller = false;
return false;
}
else if (rt->data > key)
{
if (!this->InsertAVL(rt->lchild, key, taller)) //未插入结点
{
return false;
}
if (taller) //二叉树长高,表示递归回到rt结点
{
switch (rt->BF)
{
case 1: //结点rt的平衡因子为1,而又在左子树新插入结点,故结点rt失衡,需调整
this->LeftBalance(rt);
taller = false; //维护状态,在失衡结点调整后,其祖父结点的平衡因子不会变,故不用更改,结束此模块递归
break;
case 0: //结点rt的平衡因子为0,在左子树插入结点,结点rt不会失衡,不用调整
rt->BF = 1;
taller = true; //插入新节点,二叉树高度增加,继续此模块递归,找到失衡结点
break;
case -1: //结点rt的平衡因子为-1,在左子树插入结点,结点rt不会失衡,不用调整
rt->BF = 0;
taller = false; //插入新节点,二叉树高度未增,结束此模块递归
break;
}
}
return true;
}
else
{
if (!this->InsertAVL(rt->rchild, key, taller)) //未插入结点
{
return false;
}
if (taller) //二叉树长高,表示递归回到rt结点
{
switch (rt->BF)
{
case 1: //结点rt的平衡因子为1,而又在右子树新插入结点,故结点rt不会失衡
rt->BF = 0;
taller = false; //插入新节点,二叉树高度未增,结束此模块递归
break;
case 0: //结点rt的平衡因子为0,在右子树插入结点,结点rt不会失衡,不用调整
rt->BF = -1;
taller = true; //插入新节点,二叉树高度增加,继续此模块递归,找到失衡结点
break;
case -1: //结点rt的平衡因子为-1,在右子树插入结点,结点rt会失衡,用调整
this->RightBalance(rt);
taller = false; //维护状态,在失衡结点调整后,其祖父结点的平衡因子不会变,故不用更改,结束此模块递归
break;
}
}
return true;
}
}
//前序遍历
void PreOrder(BTNode<T> *rt)
{
if (rt)
{
cout << rt->data << " ";
this->PreOrder(rt->lchild);
this->PreOrder(rt->rchild);
}
}
//中序遍历
void InOrder(BTNode<T> *rt)
{
if(rt)
{
this->InOrder(rt->lchild);
cout<<rt->data<<" ";
this->InOrder(rt->rchild);
}
}
public:
//构造函数
AVLTree() : root(NULL) {}
//拷贝构造函数
AVLTree(const AVLTree<T> &t) {}
//销毁二叉树
void Destory()
{
this->Destory(this->root);
this->root=NULL;
}
//析构函数
~AVLTree()
{
this->Destory(this->root);
}
//前序遍历
void PreOrder()
{
this->PreOrder(this->root);
}
//中序遍历
void InOrder()
{
this->InOrder(this->root);
}
//二叉树查找
bool Search(T key, BTNode<T> *&p = NULL)
{
return this->SearchAVL(this->root, key, p, NULL);
}
//插入操作
bool Insert(T key)
{
bool p;
return this->InsertAVL(this->root, key, p);
}
};
int main()
{
AVLTree<int> temp;
for (int i = 0; i < 10; i++)
{
temp.Insert(i);
}
temp.PreOrder();
cout<<endl;
temp.InOrder();
cout<<endl;
system("pause");
return 0;
}
以上是关于AVL平衡二叉树的主要内容,如果未能解决你的问题,请参考以下文章