__4.4 平衡二叉树

#include "pch.h"
#include "__0 Basic_operation.h"
#include 

#define LH +1		//左高
#define EH  0		//等高
#define RH -1		//右高


/*对以p为根的二叉排序树做左旋处理*/
/*处理之后p指向新的树根节点,即旋转处理之前的右子树的根节点0*/
void L_Rotate(BiTree *p)
{
	BiTree R = (*p)->rchild;		//R指向p的右子树的根节点
	(*p)->rchild = R->lchild;		//R的左子树挂接为p的右子树
	R->lchild = *p;		//p变为R的左子树
	*p = R;				//R变为新的根节点,P指向新的根节点
}

/*对以p为根的二叉排序树做右旋处理*/
/*处理之后p指向新的树根节点,即旋转处理之前的左子树的根节点*/
void R_Rotate(BiTree *p)
{
	BiTree L = (*p)->lchild;		//L指向p左子树的根节点
	(*p)->lchild = L->rchild;		//L的右子树挂接为p的左子树
	L->rchild = *p;		//p变为L的右子树
	*p = L;				//L变为新的根节点,P指向新的根节点
}



/*对以指针T所指结点为根的二叉树做左平衡旋转处理,即对T进行右旋处理*/
/*算法结束时,T指向新的根节点*/
void LeftBalance(BiTree* T) {
	BiTree L = (*T)->lchild;		//L指向T的左子树根节点
	switch (L->bf) {	//检查T的左子树的平衡度,并做相应的处理
	case LH:			//新节点插入在T的左孩子的左子树上,要做单右旋处理
		(*T)->bf = L->bf = EH;
		R_Rotate(T);
		break;
	case RH:		//新节点插入在T的左孩子的右子树上,要做双旋处理
		auto Lr = L->rchild;	//Lr指向T的左孩子的右子树根
		switch (Lr->bf) {		//修改T及其左孩子的平衡因子
			case LH: (*T)->bf = RH;
				L->bf = EH;
				break;
			case EH: (*T)->bf = L->bf = EH;
				break;
			case RH: (*T)->bf = EH;
				L->bf = LH;
				break;
		}
		Lr->bf = EH;
		L_Rotate(&(*T)->lchild);	//对T的左子树做左旋平衡处理
		R_Rotate(T);		//对T右旋平衡处理
	}
}

/*对以指针T所指结点为根的二叉树做右平衡旋转处理,即对T进行左旋处理*/
/*算法结束时,T指向新的根节点*/
void RightBalance(BiTree* T) {
	BiTree R = (*T)->rchild;		//R指向T的右子树根节点
	switch (R->bf) {	//检查T的右子树的平衡度,并做相应的处理
	case RH:			//新节点插入在T的右孩子的右子树上,要做单左旋处理
		(*T)->bf = R->bf = EH;
		L_Rotate(T);
		break;
	case LH:		//新节点插入在T的右孩子的左子树上,要做双旋处理
		auto Rl = R->lchild;	//Rl指向T的右孩子的左子树根
		switch (Rl->bf) {		//修改T及其右孩子的平衡因子
			case LH: (*T)->bf = EH;
				R->bf = RH;
				break;
			case EH: (*T)->bf = R->bf = EH;
				break;
			case RH: (*T)->bf = LH;
				R->bf = EH;
				break;
		}
		Rl->bf = EH;
		R_Rotate(&(*T)->rchild);	//对T的左子树做左旋平衡处理
		L_Rotate(T);		//对T右旋平衡处理
	}
}



/*若在平衡二叉树T中不存在和e相同的节点,则插入一个数据元素为e的新节点并返回true*/
/*否则返回false。若因插入而使二叉排序树失去平衡,则作旋转平衡处理,布尔变量taller标记T长高与否*/
bool InsertAVL(BiTree* T, int e, bool* taller)
{
	if (!*T) {		//插入新节点,树长高,置taller为true
		*T = new BiTNode(e);		//新节点值为e,bf为EH,左右孩子指针默认为nullptr
		(*T)->bf = EH;
		*taller = true;
	}
	else {
		if (e == (*T)->data) {		//树中已存在和e相同的节点,不再插入
			*taller = false;
			return false;
		}
		if (e < (*T)->data) {		//应继续在T的左子树中进行搜索
			if (!InsertAVL(&(*T)->lchild, e, taller))	//未插入
				return false;
			if (*taller) {				//已插入e到T的左子树且T的左子树长高
				switch ((*T)->bf) {		//检查T的平衡度
					case LH:			//原本左子树比右子树高,需要做左平衡处理
						LeftBalance(T);
						*taller = false;
						break;
					case EH:			//原本左右子树等高,现因左子树增高而树增高
						(*T)->bf = LH;
						*taller = true;
						break;
					case RH:			//原本右子树比左子树高,现左右子树等高
						(*T)->bf = EH;
						*taller = false;
						break;
				}
			}
		}
		else {		//应继续在T的右子树中进行搜索
			if (!InsertAVL(&(*T)->rchild, e, taller))	//未插入
				return false;
			if (*taller) {				//已插入e到T的右子树且T的右子树长高
				switch ((*T)->bf) {		//检查T的平衡度
					case LH:			//原本左子树比右子树高,现左右子树等高
						(*T)->bf = EH;
						*taller = false;
						break;
					case EH:			//原本左右子树等高,现因右子树增高而树增高
						(*T)->bf = RH;
						*taller = true;
						break;
					case RH:			//原本右子树比左子树高,需要做右平衡处理
						RightBalance(T);
						*taller = false;
						break;
				}
			}
		}
	}
	return true;		//插入成功
}



bool DeleteAVL(BiTree* T, int e, bool* shorter);

/*从平衡二叉树中删除节点p,并重接他的左右子树,用shorter标识以p为根节点的树是否变矮了*/
bool DeleteP(BiTree* p, bool* shorter) {
	if ((*p)->rchild == nullptr) {		//右子树空则只需重接他的左子树,树p变矮
		BiTree q = *p;
		*p = (*p)->lchild;
		delete q;
		*shorter = true;
	}
	else if ((*p)->lchild == nullptr) {		//左子树空则只需重接他的右子树,树p变矮
		BiTree q = *p;
		*p = (*p)->rchild;
		delete q;
		*shorter = true;
	}
	else {		//左右子树均不空
		BiTree q = *p;
		BiTree s = (*p)->lchild;	//s找到左顶点,然后向右走到尽头
		while (s->rchild) {
			q = s;
			s = s->rchild;
		}

	/*	最关键的一步		*/
		/* s已走到p的左孩子的最右端,此时s只有左子树或无子树,此时转化为从p开始寻找s的值并删除,
		   在回溯的过程中自动调整p至s的所有节点的平衡,最后将原s的值填到原p所指结点即可*/
		int data = s->data;
		BiTree* initP = p;			//原p所指结点,因为调整后p指向新的根节点,应该将s的值填入最开始p所指的结点
		DeleteAVL(p, s->data, shorter);
		(*initP)->data = data;
	}
	return true;
}

/*若在平衡二叉树T中存在值和e相同的节点,则删除数据元素为e的节点并返回true*/
/*否则返回false。若因删除而使二叉排序树失去平衡,则作旋转平衡处理,布尔变量shorter标记T变矮与否*/
bool DeleteAVL(BiTree* T, int e, bool* shorter)
{
	if (!*T) {		//T中不存在元素e,返回失败,树高度不变
		*shorter = false;
		return false;
	}
	else {
		if (e < (*T)->data) {			//继续在T的左子树中进行删除
			if (!DeleteAVL(&(*T)->lchild, e, shorter))	//删除失败,返回失败信息
				return false;
			if (*shorter) {			 //在T的左子树中删除成功,并且T的左子树变矮了
				switch ((*T)->bf) {	 //检查T的平衡度
					case LH:		 //原本T的左子树比右子树高
						(*T)->bf = EH;		//现在T的左右子树等高
						*shorter = true;	//树T的高度降低
						break;
					case EH:		//原本左右子树等高
						(*T)->bf = RH;		//现在T的右子树比左子树高
						*shorter = false;	//树T的高度不变
						break;
					case RH:		//原本T的右子树比左子树高,现在右子树比左子树高2,需要进行右平衡处理
						RightBalance(T);
						*shorter = true;	//树T的高度降低
						break;
				}
			}
			return true;
		}
		else if (e > (*T)->data) {			//继续在T的右子树中进行删除
			if (!DeleteAVL(&(*T)->rchild, e, shorter))	//删除失败,返回失败信息
				return false;
			if (*shorter) {			 //在T的右子树中删除成功,并且T的右子树变矮了
				switch ((*T)->bf) {	 //检查T的平衡度
					case LH:		 //原本T的左子树比右子树高,现在左子树比右子树高2,需要进行左平衡处理
						LeftBalance(T);
						*shorter = true;	//树T的高度降低
						break;
					case EH:		 //原本T的左右子树等高
						(*T)->bf = LH;		//现在T的左子树比右子树高
						*shorter = false;	//树T的高度不变
						break;
					case RH:		 //原本T的右子树比左子树高
						(*T)->bf = EH;		//现在T的左右子树等高
						*shorter = true;	//树T的高度降低
						break;
				}
			}
			return true;
		}
		else {		
			//e == (*T)->data 找到节点T,对其进行删除,返回删除结果,删除后T指向新树的根节点
			//用shorter表示新树T是否变矮了
			return DeleteP(T, shorter);
		}
	}
}



int main() {
	vector vec{ 3, 2, 1, 4, 5, 6, 7, 10, 9, 8 };
	vector vec2{ 10, 8, 12, 5, 9, 13, 3 };

	BiTree T = nullptr;
	bool taller; 
	for (size_t i = 0; i < vec2.size(); ++i)
		InsertAVL(&T, vec2[i], &taller);
	levelOrder(T);

	bool shorter;
	DeleteAVL(&T, 12, &shorter);
	levelOrder(T); 

	return 0;
}

 

你可能感兴趣的:(数据结构及算法)