算法-AVL树的插入

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、有众多的根结点

    原文作者:AVL树
    原文地址: https://blog.csdn.net/tang_jin2015/article/details/8615650
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞