AVL树的插入
AVL树是一种平衡二叉树,虽然删除的复杂度。以及出现的情况比红黑树简单,但是要不断的回溯
本文对2的因子直接一步进行右旋,相应的是一步的左旋
AVL树的查找的确是比红黑树更快。但是平衡性要求相当的大。以至于若是分布不均的话进行的操作回比红黑树多
代码:
template<class T>
void AVL_Tree<T>::AVL_TREE_INSERT(AVL_Tree<T>*avlTree,T key)
{
if (avlTree->root==NULL)//若根结点为空
{
avlTree->root=new AVL_Node<T>(key);
}
else
{
AVL_Node<T>*temp=avlTree->root;
AVL_Node<T>*parentNode=temp;
while(temp)
{
parentNode=temp;
if (key<temp->key)//若小于当前结点的键值则到左子树查找
{
temp=temp->leftChild;
}
else if (key>temp->key)//若大于当前结点的键值则到右子树查找
{
temp=temp->rightChild;
}
}
if (parentNode->key>key)
{
temp=parentNode->leftChild=new AVL_Node<T>(key);//将值赋给这个结点
}
else
{
temp=parentNode->rightChild=new AVL_Node<T>(key);
}
temp->parent=parentNode;
AVL_TREE_BALANCE(avlTree,temp);
}
nodeNum++;//树中结点的数目加1
}
//关键点在于计算平衡因子。左右子树的个数。
template<class T>
bool AVL_Tree<T>::RotateLeft(AVL_Tree<T>*avlTree,AVL_Node<T>*node)
{
//主要思想:1、获取节点右子树最大的元素,若没有右子树那么旋转节点为本身。
//若不为原来的node,设置旋转结点的父亲结点的孩子结点,将旋转结点的左子树赋值于旋转节点父亲结点的右子树,没有左子树的情况也适应
//设置旋转结点的左子树,也就是原来的祖父结点,同时设置祖父节点的父亲结点
//设置旋转结点的右子树,包括左子树的父亲结点。若node与旋转结点是同一个结点,这步省去
//设置旋转结点的父亲结点。判断原来祖父结点为左子树?右子树?
if (node==NULL)
{
return false;
}
AVL_Node<T>*parentNode=node->parent;
AVL_Node<T>*rotate_node=node->rightChild;
while(rotate_node->leftChild)
{
rotate_node=rotate_node->leftChild;
}
if (rotate_node!=node->rightChild)
{
rotate_node->parent->leftChild=rotate_node->rightChild;//将旋转节点的左子树赋值于旋转结点的右子树,这里包括没有
//左子树的情况。也就是将旋转节点的右子树置为空
if (rotate_node->rightChild)
{
rotate_node->parent->leftChild->parent=rotate_node->parent;
}
rotate_node->rightChild=node->rightChild;//将node置为旋转结点的右子树
rotate_node->rightChild->parent=rotate_node;//同时让它的父亲指向旋转结点
}
rotate_node->leftChild=node;
rotate_node->leftChild->parent=rotate_node;
rotate_node->leftChild->rightChild=NULL;//左子树的孩子设为空
if (parentNode==NULL)//处理旋转结点的父亲结点
{
rotate_node->parent=NULL;
avlTree->root=rotate_node;
}
else
{
if(parentNode==parentNode->leftChild)
{
parentNode->leftChild=rotate_node;
}
else
{
parentNode->rightChild=rotate_node;
}
rotate_node->parent=parentNode;
}
return true;
}
template<class T>//同时包括了这个节点有无右子树的情况
bool AVL_Tree<T>::RotateRight(AVL_Tree<T>*avlTree,AVL_Node<T>*node)
{
if(node==NULL)//若这个节点不存在返回false
{
return false;
}
AVL_Node<T>*parentNode=node->parent;//父亲结点
AVL_Node<T>*rotate_node=node->leftChild;
while(rotate_node->rightChild)//找到要旋转的结点
{
rotate_node=rotate_node->rightChild;
}
if (rotate_node!=node->leftChild)//若输入的结点有有右子树
{
rotate_node->parent->rightChild=rotate_node->leftChild;//将待旋转结点的左子赋予父亲结点的右子树
if (rotate_node->leftChild)
{
rotate_node->parent->rightChild->parent=rotate_node->parent;
}
rotate_node->leftChild=node->leftChild;//若输入结点就是待旋转节点,那么成为自己为自己的父结点
rotate_node->leftChild->parent=rotate_node;
}
rotate_node->rightChild=node;//将输入结点的父亲结点右旋,成为旋转结点的右子树
rotate_node->rightChild->parent=rotate_node;//旋转为右子树的父亲结点指针指向这个旋转结点
rotate_node->rightChild->leftChild=NULL;//左子树的孩子指针为空
if (parentNode==NULL)
{
rotate_node->parent=NULL;
avlTree->root=rotate_node;//若父亲结点为根结点,这个旋转的结点将成为新的根结点
}
else
{
if(node==parentNode->leftChild)
{
parentNode->leftChild=rotate_node;
}
else
{
parentNode->rightChild=rotate_node;
}//将祖父节点的孩子结点指针指向这个新的父亲结点
rotate_node->parent=parentNode;//将它的父亲指针指向祖父结点
}
return true;
}
template<class T>//得到树的高度
int AVL_Tree<T>::AVL_TREE_HIGH(AVL_Node<T>*node)
{
if (node==NULL)
{
return 0;
}
else
{
int high=0;
int leftHigh=AVL_TREE_HIGH(node->leftChild);
int rightHigh=AVL_TREE_HIGH(node->rightChild);
high=leftHigh>rightHigh?(leftHigh+1):(rightHigh+1);
return high;
}
}
平衡化:
template<class T>
void AVL_Tree<T>::AVL_TREE_BALANCE(AVL_Tree<T>*avlTree,AVL_Node<T>* node)
{
while(node)//可能要进行回溯
{
int rightHight=0;
int leftHight=0;
if (node->leftChild)//当删除之后不为空,但是值是不一样的
{
leftHight=AVL_TREE_HIGH(node->leftChild);
}
if(node->rightChild)
{
rightHight=AVL_TREE_HIGH(node->rightChild);
}
int balanceData=leftHight-rightHight;
if (balanceData==2)//1、为LL或者是LR结构
{
RotateRight(avlTree,node);
}
else if(balanceData==-2)//2、为RR结构或者是RL结构
{
RotateLeft(avlTree,node);
}
node=node->parent;
}
}
小结:、删除代码比想象中负责,使用拷贝删除
2、遇到的问题:野指针,在删除之后应该将结点的值设为NULL
3、求平衡因子的时候在加入没有考虑到,但是在删除的时候就应该是从当前结点计算平衡因子。
4、有众多的根结点