平衡二叉树

2022-05-05 19:22:17 浏览数 (1)

定义

最小不平衡子树

基本思想

构造平衡二叉树

二叉平衡树调整的四种类型

总结

完整代码

代码语言:javascript复制
#include<iostream>
using namespace std;
//平衡二叉树
//定义节点结构体
typedef struct BiNode 
{
	int data;//数据域
	int bf;//平衡因子
	BiNode* lchild, *rchild;
}BiTNode,*BiTree;


//左旋就是让最小不平衡子树的根节点成为它右孩子的左孩子
//右旋就是让最小不平衡子树的根节点成为它左孩子的右孩子

//右旋----左子树太重
void R_Rotate(BiTree& oldRoot)//这里要改变二叉树的形态,需要地址传递
{
	//通过右旋,新根的右孩子指向老根,其原本的右孩子要成为老根的左孩子
	BiTree newRoot = oldRoot->lchild;//新根是最小不平衡子树的根节点的左孩子
	//下面这一步操作来源于二叉排序树的规则:左根右
	oldRoot->lchild = newRoot->rchild;//老根的左孩子指向新根的右孩子,老根的右孩子原本是新根
	//新根的右孩子指向老根
	newRoot->rchild = oldRoot;
    //老根指向新的根节点
	oldRoot = newRoot;
}
//左旋----右子树太重
void L_Rotate(BiTree& oldRoot)
{
	//通过左旋,新根的左孩子指向老根,其原本的左孩子要成为老根的右孩子
	BiTree newRoot = oldRoot->rchild;//新根是最小不平衡子树的右孩子
	oldRoot->rchild = newRoot->lchild;//老根的右孩子指向新根的左孩子,老根的右孩子原本是新根
	//新根的左孩子指向老根
	newRoot->lchild = oldRoot;
	//老根指向新的根节点
	oldRoot = newRoot;
}
//左平衡旋转处理---LL,LR的情况处理
#define LH 1//左高
#define EH 0//等高
#define RH -1//右高
void LeftBalance(BiTree& oldRoot)//指向最小不平衡子树的根节点
{
	BiTree newRoot,Lr;//newRoot指向oldRoot的左孩子,Lr是newRoot的右孩子----这里是为了判断LR的情况发生
	newRoot = oldRoot->lchild;
	//因为传入的oldRoot根节点的bf大于1,是最小不平衡子树的根节点
	//因此下面我们要对oldRoot下面的左子树newRoot的bf进行判断,看是LL还是LR的情况
	switch (newRoot->bf)
	{
	case LH://LL的情况---右旋处理,处理完后,最小不平衡子树变为平衡二叉树
	{
		oldRoot->bf = newRoot->bf = EH;
		R_Rotate(oldRoot);//传入最小不平衡子树的根节点
		break;	
	}
	case RH://LR的情况---双旋处理---先左旋后右旋
	{
		//下面我们要对newRoot的右孩子的平衡因子进行判断
		//新节点插入在oldRoot的左孩子的右子树上,下面我们要判断,新节点插入后,左孩子的右子树的平衡因子,因为情况不同,最后节点移动情况也会有区别
		Lr = newRoot->rchild;
		switch (Lr->bf)
		{
		//如果Lr的左孩子处增加一个新节点,那么因为最后一次是右旋转,如果newRoot的lr有右孩子便会把该右孩子分配给oldRoot
		//这样一来,oldRoot最后的bf就是0,反之如果没有右孩子那么oldRoot最后的bf就是-1
		//同理如果有左孩子,那么会移动给newRoot,让其最后的bf值为0,如果没有,bf为-1
		case LH://新节点插入后,Lr增加了一个左孩子,右孩子为空
		{
			//Lr新增的节点变为了左孩子,没有右孩子
			newRoot->bf = EH;
			oldRoot->bf = RH;
			break;
		}
		case EH://新节点插入后,Lr的左右孩子均存在
		{
			newRoot->bf = oldRoot->bf = EH;
			break;
		}
		case RH://Lr新增的节点变为了右孩子,没有左孩子
		{
			oldRoot->bf = EH;
			newRoot->bf = LH;
			break;
		}
		//调整完后,初始化Lr的平衡因子
		Lr->bf = EH;
		//先左旋,后右旋
		L_Rotate(oldRoot->lchild);
		R_Rotate(oldRoot);
		}
	}
	}
}
//右平衡旋转处理------RR,RL的情况处理---平衡右子树过重的情况
void RightBalance(BiTree& oldRoot)
{
	BiNode* newRoot = oldRoot->rchild;//新根是原来最小不平衡树根的右孩子
	//下面要判断新增加的节点是构成RR型还是RL型---根据newRoot的bf值进行判断
	switch (newRoot->bf)
	{
	case RH://RR型
	{
		//进行左旋
		newRoot->bf = oldRoot->bf = EH;
		L_Rotate(oldRoot);
		break;
	}
	case LH://RL型---需要先右旋,再左旋
	{
		//RL指向oldRoot的右孩子newRoot的左子树
		//因为如果是RL型,新的节点会添加在newRoot的左子树下面
		//下面需要判断,新节点添加后,newRoot的左子树平衡因子情况,不同的情况,最后节点移动分配情况也会不同
		BiNode* RL = newRoot->lchild;
		switch (RL->bf)
		{
			//下面我们需要判断,这个新的左孩子添加后,
            //一会旋转完后,这个左孩子会分配给谁,还是原地不动,如果分配给了别的节点,会不会导致别的节点的平衡因子变化
		case LH://左高---newRoot左孩子为根节点的下面新添加了一个左孩子,没有右孩子
		{
			//口诀:左高分配给old,分配给谁,谁平衡,没分到的缺少一个左孩子,右高
			oldRoot->bf = EH;
			newRoot->bf = RH;
			break;
		}
		case EH:
		{
			oldRoot->bf = newRoot->bf = EH;
			break;
		}
		case RH://右高---newRoot左孩子为根节点的下面新添加了一个右孩子,没有左孩子
		{
			//口诀:右高分配给new,分配给谁,谁平衡,没分到的缺少一个右孩子,左高
			oldRoot->bf = LH;
			newRoot->bf = EH;
			break;
		}
		RL->bf = EH;
		//先右旋后左旋
		R_Rotate(oldRoot->rchild);
		L_Rotate(oldRoot);
		}
	}
	}
}
//二叉平衡树的插入操作
//如果二叉平衡树中不存在与Key值相等的值,就进行插入返回true,否则返回false表示插入失败
bool InsertAVL(BiTree& Root, int key, bool& taller)
{
	//找到正确位置可以进行插入操作
	if (!Root)//找到空的位置,表示可以在此位置插入
	{
		Root = new BiNode;
		Root->data = key;
		Root->lchild = Root->rchild = NULL;
		Root->bf = EH;//因为新插入的节点,左右子树都为空
		taller = true;
	}
	else 
	{
		//出现重复值
		if (Root->data == key)
		{
			taller = false;
			return false;
		}
		//否则继续查找
		if (key < Root->data)//去左子树里面查找
		{
			if (!InsertAVL(Root->lchild, key, taller))//如果插入不成功---出现重复值
			{
				return false;
			}
			if (taller)//已经插入到Root的左子树中,并且左子树长高
			{
				switch (Root->bf)//判断原本以Root为根的节点的平衡度
				{
				case LH://如果原本Root的左子树就比右子树高,再在左子树下面插入一个新节点,会造成LL型或者LR型,需要做左平衡处理
				{
					LeftBalance(Root);
					//做出平衡处理后,高度不变
					taller = false;
					break;
				}
				case EH://原本Root的左右子树等高,现在因为左子树的增高而树增高
				{
					Root->bf = LH;
					taller = true;
					break;
				}
				case RH://原本Root的右子树比左子树高,现在左右子树等高
				{
					Root->bf = EH;
					taller = false;
					break;
				}
		         }
			}
		}
		else //否则去右子树里面查找
		{
			if (!InsertAVL(Root->rchild, key, taller))//没插入---出现重复值
			{
				return false;
			}
			if (taller)//如果插入到Root的右子树中并且右子树长高
			{
				switch (Root->bf)
				{
				case LH://原本左子树比右子树高,现在左右子树等高,高度不变
				{
					Root->bf = EH;
					taller = false;
					break;
				}
				case EH://原本左右子树等高,现在右边更高
				{
					Root->bf = RH;
					taller = true;
					break;
				}
				case RH://原本就是右边高,现在右边更高,需要进行右平衡处理
				{
					taller = false;//右平衡处理后,高度不改变,Root的bf会在右平衡处理里面改变
					RightBalance(Root);
					break;
				}
				}
			}

		}
	}
	return true;
}
//打印二叉平衡树
//递归三要素:
//1.结束条件---当前节点为空
//2.递归内容---按照左根右的顺序打印二叉平衡树
//3.返回值---无返回值
void display(BiTree root)
{
	//中序遍历
	if (root == NULL)
		return;
	display(root->lchild);
	cout << root->data << " ";
	display(root->rchild);
}
//下面构建二叉平衡树
void creatAVL()
{
	int v[10] = { 3,2,1,4,5,6,7,10,9,8 };
	BiTree root = NULL;
	bool taller = false;
	for (int i = 0; i < 10; i  )
	{
		InsertAVL(root, v[i], taller);
	}
	cout << "打印二叉平衡树:" << " ";
	display(root);
	cout << endl;
	if (taller)
	{
		cout << "大树长高高,嘻嘻嘻" << endl;
	}
	else 
	{
		cout << "大树没长高,呜呜呜..." << endl;
	}
}
int main()
{
	creatAVL();
	system("pause");
	return 0;
}

这里大树之所以没长高,是因为taller记录的最后一次旋转是没有改变大树高度

增加二叉平衡树查找后的完整代码:

代码语言:javascript复制
#include<iostream>
using namespace std;
//平衡二叉树
//定义节点结构体
typedef struct BiNode 
{
	int data;//数据域
	int bf;//平衡因子
	BiNode* lchild, *rchild;
}BiTNode,*BiTree;


//左旋就是让最小不平衡子树的根节点成为它右孩子的左孩子
//右旋就是让最小不平衡子树的根节点成为它左孩子的右孩子

//右旋----左子树太重
void R_Rotate(BiTree& oldRoot)//这里要改变二叉树的形态,需要地址传递
{
	//通过右旋,新根的右孩子指向老根,其原本的右孩子要成为老根的左孩子
	BiTree newRoot = oldRoot->lchild;//新根是最小不平衡子树的根节点的左孩子
	//下面这一步操作来源于二叉排序树的规则:左根右
	oldRoot->lchild = newRoot->rchild;//老根的左孩子指向新根的右孩子,老根的右孩子原本是新根
	//新根的右孩子指向老根
	newRoot->rchild = oldRoot;
    //老根指向新的根节点
	oldRoot = newRoot;
}
//左旋----右子树太重
void L_Rotate(BiTree& oldRoot)
{
	//通过左旋,新根的左孩子指向老根,其原本的左孩子要成为老根的右孩子
	BiTree newRoot = oldRoot->rchild;//新根是最小不平衡子树的右孩子
	oldRoot->rchild = newRoot->lchild;//老根的右孩子指向新根的左孩子,老根的右孩子原本是新根
	//新根的左孩子指向老根
	newRoot->lchild = oldRoot;
	//老根指向新的根节点
	oldRoot = newRoot;
}
//左平衡旋转处理---LL,LR的情况处理
#define LH 1//左高
#define EH 0//等高
#define RH -1//右高
void LeftBalance(BiTree& oldRoot)//指向最小不平衡子树的根节点
{
	BiTree newRoot,Lr;//newRoot指向oldRoot的左孩子,Lr是newRoot的右孩子----这里是为了判断LR的情况发生
	newRoot = oldRoot->lchild;
	//因为传入的oldRoot根节点的bf大于1,是最小不平衡子树的根节点
	//因此下面我们要对oldRoot下面的左子树newRoot的bf进行判断,看是LL还是LR的情况
	switch (newRoot->bf)
	{
	case LH://LL的情况---右旋处理,处理完后,最小不平衡子树变为平衡二叉树
	{
		oldRoot->bf = newRoot->bf = EH;
		R_Rotate(oldRoot);//传入最小不平衡子树的根节点
		break;	
	}
	case RH://LR的情况---双旋处理---先左旋后右旋
	{
		//下面我们要对newRoot的右孩子的平衡因子进行判断
		//新节点插入在oldRoot的左孩子的右子树上,下面我们要判断,新节点插入后,左孩子的右子树的平衡因子,因为情况不同,最后节点移动情况也会有区别
		Lr = newRoot->rchild;
		switch (Lr->bf)
		{
		//如果Lr的左孩子处增加一个新节点,那么因为最后一次是右旋转,如果newRoot的lr有右孩子便会把该右孩子分配给oldRoot
		//这样一来,oldRoot最后的bf就是0,反之如果没有右孩子那么oldRoot最后的bf就是-1
		//同理如果有左孩子,那么会移动给newRoot,让其最后的bf值为0,如果没有,bf为-1
		case LH://新节点插入后,Lr增加了一个左孩子,右孩子为空
		{
			//Lr新增的节点变为了左孩子,没有右孩子
			newRoot->bf = EH;
			oldRoot->bf = RH;
			break;
		}
		case EH://新节点插入后,Lr的左右孩子均存在
		{
			newRoot->bf = oldRoot->bf = EH;
			break;
		}
		case RH://Lr新增的节点变为了右孩子,没有左孩子
		{
			oldRoot->bf = EH;
			newRoot->bf = LH;
			break;
		}
		//调整完后,初始化Lr的平衡因子
		Lr->bf = EH;
		//先左旋,后右旋
		L_Rotate(oldRoot->lchild);
		R_Rotate(oldRoot);
		}
	}
	}
}
//右平衡旋转处理------RR,RL的情况处理---平衡右子树过重的情况
void RightBalance(BiTree& oldRoot)
{
	BiNode* newRoot = oldRoot->rchild;//新根是原来最小不平衡树根的右孩子
	//下面要判断新增加的节点是构成RR型还是RL型---根据newRoot的bf值进行判断
	switch (newRoot->bf)
	{
	case RH://RR型
	{
		//进行左旋
		newRoot->bf = oldRoot->bf = EH;
		L_Rotate(oldRoot);
		break;
	}
	case LH://RL型---需要先右旋,再左旋
	{
		//RL指向oldRoot的右孩子newRoot的左子树
		//因为如果是RL型,新的节点会添加在newRoot的左子树下面
		//下面需要判断,新节点添加后,newRoot的左子树平衡因子情况,不同的情况,最后节点移动分配情况也会不同
		BiNode* RL = newRoot->lchild;
		switch (RL->bf)
		{
			//下面我们需要判断,这个新的左孩子添加后,
            //一会旋转完后,这个左孩子会分配给谁,还是原地不动,如果分配给了别的节点,会不会导致别的节点的平衡因子变化
		case LH://左高---newRoot左孩子为根节点的下面新添加了一个左孩子,没有右孩子
		{
			//口诀:左高分配给old,分配给谁,谁平衡,没分到的缺少一个左孩子,右高
			oldRoot->bf = EH;
			newRoot->bf = RH;
			break;
		}
		case EH:
		{
			oldRoot->bf = newRoot->bf = EH;
			break;
		}
		case RH://右高---newRoot左孩子为根节点的下面新添加了一个右孩子,没有左孩子
		{
			//口诀:右高分配给new,分配给谁,谁平衡,没分到的缺少一个右孩子,左高
			oldRoot->bf = LH;
			newRoot->bf = EH;
			break;
		}
		RL->bf = EH;
		//先右旋后左旋
		R_Rotate(oldRoot->rchild);
		L_Rotate(oldRoot);
		}
	}
	}
}
//二叉平衡树的插入操作
//如果二叉平衡树中不存在与Key值相等的值,就进行插入返回true,否则返回false表示插入失败
bool InsertAVL(BiTree& Root, int key, bool& taller)
{
	//找到正确位置可以进行插入操作
	if (!Root)//找到空的位置,表示可以在此位置插入
	{
		Root = new BiNode;
		Root->data = key;
		Root->lchild = Root->rchild = NULL;
		Root->bf = EH;//因为新插入的节点,左右子树都为空
		taller = true;
	}
	else 
	{
		//出现重复值
		if (Root->data == key)
		{
			taller = false;
			return false;
		}
		//否则继续查找
		if (key < Root->data)//去左子树里面查找
		{
			if (!InsertAVL(Root->lchild, key, taller))//如果插入不成功---出现重复值
			{
				return false;
			}
			if (taller)//已经插入到Root的左子树中,并且左子树长高
			{
				switch (Root->bf)//判断原本以Root为根的节点的平衡度
				{
				case LH://如果原本Root的左子树就比右子树高,再在左子树下面插入一个新节点,会造成LL型或者LR型,需要做左平衡处理
				{
					LeftBalance(Root);
					//做出平衡处理后,高度不变
					taller = false;
					break;
				}
				case EH://原本Root的左右子树等高,现在因为左子树的增高而树增高
				{
					Root->bf = LH;
					taller = true;
					break;
				}
				case RH://原本Root的右子树比左子树高,现在左右子树等高
				{
					Root->bf = EH;
					taller = false;
					break;
				}
		         }
			}
		}
		else //否则去右子树里面查找
		{
			if (!InsertAVL(Root->rchild, key, taller))//没插入---出现重复值
			{
				return false;
			}
			if (taller)//如果插入到Root的右子树中并且右子树长高
			{
				switch (Root->bf)
				{
				case LH://原本左子树比右子树高,现在左右子树等高,高度不变
				{
					Root->bf = EH;
					taller = false;
					break;
				}
				case EH://原本左右子树等高,现在右边更高
				{
					Root->bf = RH;
					taller = true;
					break;
				}
				case RH://原本就是右边高,现在右边更高,需要进行右平衡处理
				{
					taller = false;//右平衡处理后,高度不改变,Root的bf会在右平衡处理里面改变
					RightBalance(Root);
					break;
				}
				}
			}

		}
	}
	return true;
}
//打印二叉平衡树
//递归三要素:
//1.结束条件---当前节点为空
//2.递归内容---按照左根右的顺序打印二叉平衡树
//3.返回值---无返回值
void display(BiTree root)
{
	//中序遍历
	if (root == NULL)
		return;
	display(root->lchild);
	cout << root->data << " ";
	display(root->rchild);
}
//二叉平衡树的查找---非递归写法
bool findNode(const BiTree root, int val, BiTree& pos)
{
	BiTree ptr = root;
	while (ptr)
	{
		if (ptr->data == val)
		{
			pos = ptr;
			return true;
		}
		else if (ptr->data > val)
		{
			ptr = ptr->lchild;//去左子树里面查找
		}
		else
		{
			ptr = ptr->rchild;
		}
	}
	return false;
}
//下面构建二叉平衡树
void creatAVL()
{
	int v[10] = { 3,2,1,4,5,6,7,10,9,8 };
	BiTree root = NULL;
	bool taller = false;
	for (int i = 0; i < 10; i  )
	{
		InsertAVL(root, v[i], taller);
	}
	cout << "打印二叉平衡树:" << " ";
	display(root);
	cout << endl;
	if (taller)
	{
		cout << "大树长高高,嘻嘻嘻" << endl;
	}
	else 
	{
		cout << "大树没长高,呜呜呜..." << endl;
	}
	cout << "查找6关键字:" << endl;
	BiTree pos = NULL;
	bool ret = findNode(root, 6, pos);
	if (ret)
		cout << "找到了" << pos->data << "关键字" << endl;
	else
		cout << "没有找到" << endl;
}
int main()
{
	creatAVL();
	system("pause");
	return 0;
}

增加二叉平衡树删除后的完整代码:

代码语言:javascript复制
#include<iostream>
using namespace std;
//平衡二叉树
//定义节点结构体
typedef struct BiNode 
{
	int data;//数据域
	int bf;//平衡因子
	BiNode* lchild, *rchild;
}BiTNode,*BiTree;


//左旋就是让最小不平衡子树的根节点成为它右孩子的左孩子
//右旋就是让最小不平衡子树的根节点成为它左孩子的右孩子

//右旋----左子树太重
void R_Rotate(BiTree& oldRoot)//这里要改变二叉树的形态,需要地址传递
{
	//通过右旋,新根的右孩子指向老根,其原本的右孩子要成为老根的左孩子
	BiTree newRoot = oldRoot->lchild;//新根是最小不平衡子树的根节点的左孩子
	//下面这一步操作来源于二叉排序树的规则:左根右
	oldRoot->lchild = newRoot->rchild;//老根的左孩子指向新根的右孩子,老根的右孩子原本是新根
	//新根的右孩子指向老根
	newRoot->rchild = oldRoot;
    //老根指向新的根节点
	oldRoot = newRoot;
}
//左旋----右子树太重
void L_Rotate(BiTree& oldRoot)
{
	//通过左旋,新根的左孩子指向老根,其原本的左孩子要成为老根的右孩子
	BiTree newRoot = oldRoot->rchild;//新根是最小不平衡子树的右孩子
	oldRoot->rchild = newRoot->lchild;//老根的右孩子指向新根的左孩子,老根的右孩子原本是新根
	//新根的左孩子指向老根
	newRoot->lchild = oldRoot;
	//老根指向新的根节点
	oldRoot = newRoot;
}
//左平衡旋转处理---LL,LR的情况处理
#define LH 1//左高
#define EH 0//等高
#define RH -1//右高
void LeftBalance(BiTree& oldRoot)//指向最小不平衡子树的根节点
{
	BiTree newRoot,Lr;//newRoot指向oldRoot的左孩子,Lr是newRoot的右孩子----这里是为了判断LR的情况发生
	newRoot = oldRoot->lchild;
	//因为传入的oldRoot根节点的bf大于1,是最小不平衡子树的根节点
	//因此下面我们要对oldRoot下面的左子树newRoot的bf进行判断,看是LL还是LR的情况
	switch (newRoot->bf)
	{
	case LH://LL的情况---右旋处理,处理完后,最小不平衡子树变为平衡二叉树
	{
		oldRoot->bf = newRoot->bf = EH;
		R_Rotate(oldRoot);//传入最小不平衡子树的根节点
		break;	
	}
	case RH://LR的情况---双旋处理---先左旋后右旋
	{
		//下面我们要对newRoot的右孩子的平衡因子进行判断
		//新节点插入在oldRoot的左孩子的右子树上,下面我们要判断,新节点插入后,左孩子的右子树的平衡因子,因为情况不同,最后节点移动情况也会有区别
		Lr = newRoot->rchild;
		switch (Lr->bf)
		{
		//如果Lr的左孩子处增加一个新节点,那么因为最后一次是右旋转,如果newRoot的lr有右孩子便会把该右孩子分配给oldRoot
		//这样一来,oldRoot最后的bf就是0,反之如果没有右孩子那么oldRoot最后的bf就是-1
		//同理如果有左孩子,那么会移动给newRoot,让其最后的bf值为0,如果没有,bf为-1
		case LH://新节点插入后,Lr增加了一个左孩子,右孩子为空
		{
			//Lr新增的节点变为了左孩子,没有右孩子
			newRoot->bf = EH;
			oldRoot->bf = RH;
			break;
		}
		case EH://新节点插入后,Lr的左右孩子均存在
		{
			newRoot->bf = oldRoot->bf = EH;
			break;
		}
		case RH://Lr新增的节点变为了右孩子,没有左孩子
		{
			oldRoot->bf = EH;
			newRoot->bf = LH;
			break;
		}
		//调整完后,初始化Lr的平衡因子
		Lr->bf = EH;
		//先左旋,后右旋
		L_Rotate(oldRoot->lchild);
		R_Rotate(oldRoot);
		}
	}
	}
}
//右平衡旋转处理------RR,RL的情况处理---平衡右子树过重的情况
void RightBalance(BiTree& oldRoot)
{
	BiNode* newRoot = oldRoot->rchild;//新根是原来最小不平衡树根的右孩子
	//下面要判断新增加的节点是构成RR型还是RL型---根据newRoot的bf值进行判断
	switch (newRoot->bf)
	{
	case RH://RR型
	{
		//进行左旋
		newRoot->bf = oldRoot->bf = EH;
		L_Rotate(oldRoot);
		break;
	}
	case LH://RL型---需要先右旋,再左旋
	{
		//RL指向oldRoot的右孩子newRoot的左子树
		//因为如果是RL型,新的节点会添加在newRoot的左子树下面
		//下面需要判断,新节点添加后,newRoot的左子树平衡因子情况,不同的情况,最后节点移动分配情况也会不同
		BiNode* RL = newRoot->lchild;
		switch (RL->bf)
		{
			//下面我们需要判断,这个新的左孩子添加后,
            //一会旋转完后,这个左孩子会分配给谁,还是原地不动,如果分配给了别的节点,会不会导致别的节点的平衡因子变化
		case LH://左高---newRoot左孩子为根节点的下面新添加了一个左孩子,没有右孩子
		{
			//口诀:左高分配给old,分配给谁,谁平衡,没分到的缺少一个左孩子,右高
			oldRoot->bf = EH;
			newRoot->bf = RH;
			break;
		}
		case EH:
		{
			oldRoot->bf = newRoot->bf = EH;
			break;
		}
		case RH://右高---newRoot左孩子为根节点的下面新添加了一个右孩子,没有左孩子
		{
			//口诀:右高分配给new,分配给谁,谁平衡,没分到的缺少一个右孩子,左高
			oldRoot->bf = LH;
			newRoot->bf = EH;
			break;
		}
		RL->bf = EH;
		//先右旋后左旋
		R_Rotate(oldRoot->rchild);
		L_Rotate(oldRoot);
		}
	}
	}
}
//二叉平衡树的插入操作
//如果二叉平衡树中不存在与Key值相等的值,就进行插入返回true,否则返回false表示插入失败
bool InsertAVL(BiTree& Root, int key, bool& taller)
{
	//找到正确位置可以进行插入操作
	if (!Root)//找到空的位置,表示可以在此位置插入
	{
		Root = new BiNode;
		Root->data = key;
		Root->lchild = Root->rchild = NULL;
		Root->bf = EH;//因为新插入的节点,左右子树都为空
		taller = true;
	}
	else 
	{
		//出现重复值
		if (Root->data == key)
		{
			taller = false;
			return false;
		}
		//否则继续查找
		if (key < Root->data)//去左子树里面查找
		{
			if (!InsertAVL(Root->lchild, key, taller))//如果插入不成功---出现重复值
			{
				return false;
			}
			if (taller)//已经插入到Root的左子树中,并且左子树长高
			{
				switch (Root->bf)//判断原本以Root为根的节点的平衡度
				{
				case LH://如果原本Root的左子树就比右子树高,再在左子树下面插入一个新节点,会造成LL型或者LR型,需要做左平衡处理
				{
					LeftBalance(Root);
					//做出平衡处理后,高度不变
					taller = false;
					break;
				}
				case EH://原本Root的左右子树等高,现在因为左子树的增高而树增高
				{
					Root->bf = LH;
					taller = true;
					break;
				}
				case RH://原本Root的右子树比左子树高,现在左右子树等高
				{
					Root->bf = EH;
					taller = false;
					break;
				}
		         }
			}
		}
		else //否则去右子树里面查找
		{
			if (!InsertAVL(Root->rchild, key, taller))//没插入---出现重复值
			{
				return false;
			}
			if (taller)//如果插入到Root的右子树中并且右子树长高
			{
				switch (Root->bf)
				{
				case LH://原本左子树比右子树高,现在左右子树等高,高度不变
				{
					Root->bf = EH;
					taller = false;
					break;
				}
				case EH://原本左右子树等高,现在右边更高
				{
					Root->bf = RH;
					taller = true;
					break;
				}
				case RH://原本就是右边高,现在右边更高,需要进行右平衡处理
				{
					taller = false;//右平衡处理后,高度不改变,Root的bf会在右平衡处理里面改变
					RightBalance(Root);
					break;
				}
				}
			}

		}
	}
	return true;
}
//打印二叉平衡树
//递归三要素:
//1.结束条件---当前节点为空
//2.递归内容---按照左根右的顺序打印二叉平衡树
//3.返回值---无返回值
void display(BiTree root)
{
	//中序遍历
	if (root == NULL)
		return;
	display(root->lchild);
	cout << root->data << " ";
	display(root->rchild);
}
//二叉平衡树的查找---非递归写法
bool findNode(const BiTree root, int val, BiTree& pos)
{
	BiTree ptr = root;
	while (ptr)
	{
		if (ptr->data == val)
		{
			pos = ptr;
			return true;
		}
		else if (ptr->data > val)
		{
			ptr = ptr->lchild;//去左子树里面查找
		}
		else
		{
			ptr = ptr->rchild;
		}
	}
	return false;
}
//删除节点的函数----删除时要注意是否破坏了平衡性,以及平衡因子的大小的变化
bool Delete(BiTree& node,bool &lower)
{
	BiTree parent, pre;
	if (node->rchild == NULL)//右子树为空,需要重接它的左子树
	{
		parent = node;
		node = node->lchild;
		free(parent);
		lower = true;
	}
	else if (node->lchild == NULL)//左子树为空,需要重接它的右子树
	{
		parent = node;
		node = node->rchild;
		free(parent);
		lower = true;
	}
	else//左右子树均不为空,我们选择删除顶点的前驱节点来替代要删除的节点
	{
		//前驱节点要去删除顶点的左子树的最下面的右孩子里面找
		parent = node;
		pre = parent->lchild;
		while (pre->rchild)
		{
			parent = pre;
			pre = pre->rchild;
		}
		node->data = pre->data;//s的data值替换为前驱值,然后把该前驱删去
		//删去的时候判断该前驱有没有左子树
		if (parent != node)//重接parent的右子树为pre的左子树
		{
			//有左子树就接,没有接空
			parent->rchild = pre->rchild;
		}
		else//重接parent的左子树
		{
			//node的左子树没有右子树,所以前驱就直接是node的左孩子
			parent->lchild = pre->lchild;
		}
		free(pre);
		lower = true;
	}
	return true;
}
//二叉平衡树的删除操作---增加三个变量
bool deleteNode(BiTree& root,int key)
{
	static bool l=false;//删除的是左节点
	static bool r=false;//删除的是右节点
	static bool lower=false;//lower判断是否删除了节点
	if (!root)//遍历到空,也没有找到对应删除元素
	{
		lower = false;
		return false;
	}
	else
	{
		if (key == root->data)
			Delete(root,lower);
		else if (key < root->data)
		{
			 deleteNode(root->lchild, key);
			l = true;
		}
		else
		{
			deleteNode(root->rchild, key);
			r = true;
		}
	}
	//判断是否有节点删除
	if (lower)
	{
		//删除的是左节点
		if (l)
		{
			switch (root->bf)//当前节点原本bf值
			{
			case LH://原本左子树高,删除后左右相等
			{
				root->bf = EH;
				lower = true;//标志位降低
				break;
			}
			case EH://原本左右平衡,删除左子树后,右高
			{
				root->bf = RH;
				lower = false;//标志位没有降低
				break;
			}
			case RH://原本右子树高,删除左子树后,要进行右平衡调整
			{
				RightBalance(root);
				lower = false;//高度没有降低,调整维持原本高度
				break;
			}
			}
		}
		else if(r)//删除的是右节点
		{
			switch (root->bf)//当前节点原本bf值
			{
			case LH://原本左子树高,删除后要进行左平衡调整
			{
				LeftBalance(root);
				lower = false;
				break;
			}
			case EH://原本左右平衡,删除右子树后,左高
			{
				root->bf = LH;
				lower = false;//标志位没有降低
				break;
			}
			case RH://原本右子树高,删除右子树后,左右平衡
			{
				root->bf = EH;
				lower =true;
				break;
			}
			}
		}

	}
}
//下面构建二叉平衡树
void creatAVL()
{
	int v[10] = { 3,2,1,4,5,6,7,10,9,8 };
	BiTree root = NULL;
	bool taller = false;
	for (int i = 0; i < 10; i  )
	{
		InsertAVL(root, v[i], taller);
	}
	cout << "打印二叉平衡树:" << " ";
	display(root);
	cout << endl;
	if (taller)
	{
		cout << "大树长高高,嘻嘻嘻" << endl;
	}
	else 
	{
		cout << "大树没长高,呜呜呜..." << endl;
	}
	cout << "查找6关键字:" << endl;
	BiTree pos = NULL;
	bool ret = findNode(root, 6, pos);
	if (ret)
		cout << "找到了" << pos->data << "关键字" << endl;
	else
		cout << "没有找到" << endl;
	cout << "删除5关键字后:" << endl;
	deleteNode(root, 5);
	display(root);
	cout << endl;
}
int main()
{
	creatAVL();
	system("pause");
	return 0;
}

0 人点赞