平衡二叉树的删除调整

0. 前言

平衡二叉树的删除可能会破坏平衡性,所以同插入一样,也需要动态的调整。在阅读之前,需要掌握二叉搜索树的节点删除平衡二叉树的插入,链接如下:

1. 平衡二叉树的删除

强调几点:

  • 1、要注意函数每个分支流程是否都有返回值(如代码一);
  • 2、如果删除了,那么这个节点就不存在了,所以对该节点的操作程序都会报错;
  • 3、如果删除了,那么返回到父节点的值是true,这时才需要进行平衡调整;如果未删除,那么就是false,相应的也不需要调整平衡;

1.1 代码一(有bug)

bool deleteAVL(LPNode* root, int key)
{
	if (*root == NULL)
		return false;
	if (key == (*root)->key)
	{
		LPNode q, s;
		if ((*root)->left == NULL && (*root)->right == NULL)
		{
			q = (*root);
			(*root) = NULL;
			delete q;
		}
		else if ((*root)->left == NULL)
		{
			q = (*root);
			*root = (*root)->right;
			delete q;
		}
		else if ((*root)->right == NULL)
		{
			q = *root;
			*root = (*root)->left;
			delete q;
		}
		else
		{
			q = *root;
			s = (*root)->left;
			while (s->right)
			{
				q = s;
				s = s->right;
			}
			(*root)->key = s->key;
			if (q != *root)
			{
				q->right = s->left;
			}
			else
			{
				q->left = s->left;
			}
		}
		return true;
	}
	else if (key > (*root)->key)
	{
		deleteAVL(&(*root)->right, key);
	}
	else
	{
		deleteAVL(&(*root)->left, key);
	}
	//更新节点深度
	renewTreeDepth(*root);
	//二叉树平衡的调整
	adjustBalance(root, key);
}

bug

1.2 代码二(正确)

bool deleteAVL(LPNode* root, int key)
{
	if (*root == NULL)
		return false;
	if (key == (*root)->key)
	{
		LPNode q, s;
		if ((*root)->left == NULL && (*root)->right == NULL)
		{
			q = (*root);
			(*root) = NULL;
			delete q;
		}
		else if ((*root)->left == NULL)
		{
			q = (*root);
			*root = (*root)->right;
			delete q;
		}
		else if ((*root)->right == NULL)
		{
			q = *root;
			*root = (*root)->left;
			delete q;
		}
		else
		{
			q = *root;
			s = (*root)->left;
			while (s->right)
			{
				q = s;
				s = s->right;
			}
			(*root)->key = s->key;
			if (q != *root)
			{
				q->right = s->left;
			}
			else
			{
				q->left = s->left;
			}
		}
		return true;
	}
	else if (key > (*root)->key)
	{
		//如果本次传进去删掉了(*root)->right,那么return回来就是true,则需要调整(*root)
		//否则没有删掉,返回回来是false,则不需要调整
		int flag = deleteAVL(&(*root)->right, key);
		if (flag)
		{
			//更新节点深度
			renewTreeDepth(*root);
			//二叉树平衡的调整
			adjustBalance(root, key);
		}
		return flag;
	}
	else
	{
		//如果本次传进去删掉了(*root)->left,那么return回来就是true,则需要调整(*root)
		//否则没有删掉,返回回来是false,则不需要调整
		int flag = deleteAVL(&(*root)->left, key);
		if (flag)
		{
			//更新节点深度
			renewTreeDepth(*root);
			//二叉树平衡的调整
			adjustBalance(root, key);
		}
		return flag;
	}
}

2. 完整代码

#include<stdio.h>
#include<stdlib.h>

typedef struct Node {
	int key;
	struct Node* left;
	struct Node* right;
	int depth;
}*LPNode;

int max(int a, int b)
{
	return a > b ? a : b;
}

int getDepth(LPNode node)
{
	if (node == NULL)
		return 0;
	return node->depth;
}

void renewTreeDepth(LPNode root)
{
	必须写成函数,不然会传进来空指针,
	//比如:int leftDepth = root->left->depth;
	int leftDepth = getDepth(root->left);
	int rightDepth = getDepth(root->right);
	root->depth = max(leftDepth, rightDepth) + 1;
}

void LL_Rotation(LPNode* root)
{
	//LL型要右旋
	LPNode cache = (*root)->left;
	(*root)->left = cache->right;
	cache->right = (*root);
	//更新调整后的高度
	renewTreeDepth(*root);
	renewTreeDepth(cache);
	//更新root的指向
	*root = cache;
}

void RR_Rotation(LPNode* root)
{

	//RR型要左旋
	LPNode cache = (*root)->right;
	(*root)->right = cache->left;
	cache->left = (*root);
	//更新调整后的高度
	renewTreeDepth(*root);
	renewTreeDepth(cache);
	//更新root的指向
	*root = cache;
}

void LR_Rotation(LPNode* root)
{
	//LR型先左旋再右旋
	RR_Rotation(&(*root)->left);
	LL_Rotation(root);
}

void RL_Rotation(LPNode* root)
{
	//RL型,先右旋再左旋
	LL_Rotation(&(*root)->right);
	RR_Rotation(root);
}

void adjustBalance(LPNode* root, int key)
{
	if (getDepth((*root)->left) - getDepth((*root)->right) > 1)
	{
		if (key < (*root)->left->key)
		{
			//LL型
			LL_Rotation(root);
		}
		else
		{
			//LR型
			LR_Rotation(root);
		}
	}
	else if (getDepth((*root)->left) - getDepth((*root)->right) < -1)
	{
		if (key > (*root)->right->key)
		{
			//RR型
			RR_Rotation(root);
		}
		else
		{
			//RL型
			RL_Rotation(root);
		}
	}
}

bool deleteAVL(LPNode* root, int key)
{
	if (*root == NULL)
		return false;
	if (key == (*root)->key)
	{
		LPNode q, s;
		if ((*root)->left == NULL && (*root)->right == NULL)
		{
			q = (*root);
			(*root) = NULL;
			delete q;
		}
		else if ((*root)->left == NULL)
		{
			q = (*root);
			*root = (*root)->right;
			delete q;
		}
		else if ((*root)->right == NULL)
		{
			q = *root;
			*root = (*root)->left;
			delete q;
		}
		else
		{
			q = *root;
			s = (*root)->left;
			while (s->right)
			{
				q = s;
				s = s->right;
			}
			(*root)->key = s->key;
			if (q != *root)
			{
				q->right = s->left;
			}
			else
			{
				q->left = s->left;
			}
		}
		return true;
	}
	else if (key > (*root)->key)
	{
		//如果本次传进去删掉了(*root)->right,那么return回来就是true,则需要调整(*root)
		//否则没有删掉,返回回来是false,则不需要调整
		int flag = deleteAVL(&(*root)->right, key);
		if (flag)
		{
			//更新节点深度
			renewTreeDepth(*root);
			//二叉树平衡的调整
			adjustBalance(root, key);
		}
		return flag;
	}
	else
	{
		//如果本次传进去删掉了(*root)->left,那么return回来就是true,则需要调整(*root)
		//否则没有删掉,返回回来是false,则不需要调整
		int flag = deleteAVL(&(*root)->left, key);
		if (flag)
		{
			//更新节点深度
			renewTreeDepth(*root);
			//二叉树平衡的调整
			adjustBalance(root, key);
		}
		return flag;
	}
}

void insertAVL(LPNode* root, int key)
{
	if (*root == NULL)
	{
		(*root) = (LPNode)malloc(sizeof(struct Node));
		if (*root == NULL)
			return;
		(*root)->key = key;
		(*root)->depth = 1;
		(*root)->left = NULL;
		(*root)->right = NULL;
	}
	else
	{
		if (key < (*root)->key)
		{
			insertAVL(&(*root)->left, key);
		}
		else if (key > (*root)->key)
		{
			insertAVL(&(*root)->right, key);
		}
	}
	//更新节点的深度
	renewTreeDepth(*root);

	//二叉树平衡的调整
	adjustBalance(root, key);
}

void midOrder(LPNode root)
{
	if (root != NULL)
	{
		midOrder(root->left);//左
		printf("%d ", root->key);
		midOrder(root->right);//右
	}
}

int main()
{
	LPNode root = NULL;
	int keyArr[6] = { 9,8,7,0,3,1};
	for (int i = 0; i < 6; i++)
	{
		insertAVL(&root, keyArr[i]);
	}
	midOrder(root);

	bool flag = deleteAVL(&root, 8);
	if (flag)
	{
		printf("已删除\n");
		midOrder(root);
	}

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值