Fork me on GitHub

AVL树的建立解析含代码(C++)

AVL树

AVL树是平衡二叉树,它可以尽可能创建“枝繁叶茂”的树,防止树枝过长过少。二叉树搜索中,会引入ASL平均查找长度的概念,表示查找所有节点的比较次数平均值。平衡二叉树的ASL相较而言较小。

思路

AVL树就是比较各个节点左右子树的深度差,当差值等于2时就需要对树结构进行改变。改变的方式有左旋、右旋、左右旋以及右左旋。判断旋转方式是看导致深度差值的结点在哪。左旋是顺时针旋转相关结点,右旋为逆时针旋转相关结点。左右旋及右左旋为左旋、右旋的组合,左右旋先右旋后左旋。
如下面图的示例:



以上图片来自陈越《数据结构》一书。
关于旋转结点的代码不是很难,RL旋和LR旋为各是两个单旋的组合,L旋和R旋的思路又都一样。因此只要搞懂一个方向的单旋即可。注意单旋时旋转结点的子结点位置的改变。具体的看代码。

代码

#include <iostream>
using namespace std;

/*avl平衡树的建立,需要判断一个节点左右两子树的深度差,差值小于2视为平衡*/
typedef struct node{
	int data;
	node* lchild;
	node* rchild;
	int height;
}*bitTree;

int max(int a,int b)
{//用于比较子树大小 
	return a>b?a:b;	
} 
int getHeight(bitTree T)
{//获取树的高度 
	int lnum,rnum,count;
	if(T){
		lnum = getHeight(T->lchild);
		rnum = getHeight(T->rchild);
		count = lnum>rnum?lnum:rnum;//比较左右子树的高度取最大值 
		return (count+1);
	}	
}
bitTree singleleftRotation(bitTree T)//左旋 
{
	bitTree B = new node;
	B = T->lchild;
	T->lchild = B->rchild;
	B->rchild = T;
	T->height = max(getHeight(T->lchild),getHeight(T->rchild))+1;
	B->height = max(getHeight(B->lchild),T->height)+1;
	return B;
}
bitTree singlerightRotation(bitTree T)
{
	bitTree B = T->rchild;
	T->rchild = B->lchild;
	B->lchild = T;
	T->height = max(getHeight(T->lchild),getHeight(T->rchild))+1;
	B->height = max(getHeight(B->rchild),T->height)+1;
}
bitTree doubleleftrightRotation(bitTree T)
{
	T->lchild = singlerightRotation(T->lchild);
	return singleleftRotation(T);
}
bitTree doublerightleftRotation(bitTree T)
{
	T->rchild = singleleftRotation(T->lchild);
	return singlerightRotation(T);
}
bitTree insert(bitTree &T,int x)
{//AVL树在插入的过程中不断判断
	if(!T)//插入一个空树 
	{
		T = new node;
		T->data = x;
		T->lchild = T->rchild = NULL;
		T->height = 1;//这里树高的初值不重要,后续的高度都会做左右子树高度对比重新取值
	}
	else if(x<T->data){//插入值在左子树中 
		T->lchild = insert(T->lchild,x);
		//对旋的判断就是看其插入的位置 
		if(getHeight(T->lchild)-getHeight(T->rchild)==2){
			if(x<T->lchild->data)//需要L旋 
				T = singleleftRotation(T);
			else//左右旋 
				T = doubleleftrightRotation(T);
		}
	}
	else if(x>T->data){//插入值在右子树中 
		T->rchild = insert(T->rchild,x);
		//对旋的判断就是看其插入的位置 
		if(getHeight(T->lchild)-getHeight(T->rchild)==2){
			if(x>T->rchild->data)//需要R旋 
				T = singlerightRotation(T);
			else//RL旋 
				T = doublerightleftRotation(T);
		}
	}
	T->height = max(getHeight(T->lchild),getHeight(T->rchild))+1;//插入了新值,树的高度加一 
	return T; 
}
int display(bitTree T)
{//先序遍历
	if(T!=NULL)
	{
		display(T->lchild);
		cout<<T->data<<" ";
		display(T->rchild);
	}
}
int main()
{
/*
   示例生成二叉树:
	            18
                   /   \
		 10     20
	       /   \   /   \
	      9    11 19   22
*/ 
	bitTree T;
	int a[7] = {9,11,19,22,18,10,20};
	for(int i = 0;i<7;i++)
		insert(T,a[i]);
	display(T);
//输出9 10 11 18 19 20 22
}

注意点

结点的单旋需要传入的结点为第一个深度不平衡的结点。多旋则是先对不平衡结点的下一个子节点单旋,后对不平衡结点再做一次单旋。
下面以RL旋做一个例子

posted @ 2021-12-31 11:11  kki_m  阅读(153)  评论(0)    收藏  举报