数据结构——平衡二叉树之删除

目录

前言

删除结点

调整结点

代码实现


前言

        我们知道,在平衡二叉树中插入一个结点可能会改变二叉树的平衡因子,使得平衡因子超过1。但是删除平衡二叉树的一个结点时也会使得二叉树的平衡因子发生改变。也会需要对树进行调整。这篇博客是说明怎么判断调整位置。想了解调整的具体细节的可以看博客数据结构——平衡二叉树(AVL树)之插入

        平衡二叉树删除结点和插入操作类似,首先先删除一个结点,然后对自下向上最近的平衡因子超过1的结点进行调整。

删除结点

        首先平衡二叉树也是一颗二叉搜索树,删除结点的方式与二叉搜索树相同。有四种情况:

  1. 删除节点为叶节点。这种情况最简单,直接将其置空,释放,然后返回给父节点即可。
  2. 删除节点有左子树没有右子树。 先保存该节点的地址(方便释放),将该节点直接等于左子树地址, 相当于该节点存的就是左子树的地址,将原来节点地址覆盖了。然后释放。
  3. 删除节点有右子树没有左子树 。与2处理相同,只是将左子树换为右子树。
  4. 既有左子树又有右子树
    可以有两种解决办法:
    1.找到左子树中的最大值,将值赋给给节点,然后将左子树最大值这个节点删除(删除可以用递归实现)
    2.找到左子树中的最小值,将值赋给给节点,然后将右子树最小值这个节点删除
    当然这样会有个弊端:当一直删除时,会导致树高度失衡,导致一边高,一边低,解决这样的办法可以删除左右子树最大最小节点交替实行。或者记录一高度,主要删除,左子树或者右子树高的那一边。

想知道二叉树的删除时如何实现的,可以看博客二叉搜索树删除结点

注意:既有左子树又有右子树时,要递归将左子树最大值或者右子树最小值删除,也需要判断是否需要调整结点。

调整结点

        通过博客平衡二叉树的调整细节,我们了解到,平衡二叉树有四种调节方式,左左旋转(LL),右左旋转(R-L),右右旋转(RR),左右旋转(L-R)。在插入时判断调整位置是通过插入结点的值和被破坏平衡因子结点的儿子结点值的大小,来判断使用哪种调整方式。那么平衡二叉树在删除时怎么判断应该使用哪种方式进行调整呢?

        首先判断删除值是在左子树还是右子树。那么怎么判断呢?当删除递归返回时,会返回到结点的左子树或者右子树。看后面代码实现就一目了然。        

  • 删除值在右子树

        判断被破坏结点的左儿子的平衡因子。如果为-1,用左右旋转调整,如果为1,用右右旋转调整。如果为0,右右或者左右调整都适合。

  • 删除结点在左子树

        判断被破坏结点的右儿子的平衡因子。如果为-1,用左左旋转调整,如果为1,用右左旋转调整。如果为0,左左或者右左调整都适合。

代码实现

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

typedef int ElementType;

typedef struct Balancetree{
	ElementType data;
	struct Balancetree *left;
	struct Balancetree *right;

}Btree;

Btree *CreateNode(ElementType x){
	Btree *node = (Btree *)malloc(sizeof(Btree));
	node->data = x;
	node->left = NULL;
	node->right = NULL;
	return node;
}
int GetHight(Btree *tree){
	if (!tree){
		return 0;
	}
	int lh = GetHight(tree->left);
	int rh = GetHight(tree->right);
	int h = lh > rh ? lh : rh;
	return h + 1;
}

//左旋
void SigleLeftCir(Btree **tree){
	Btree *a = *tree;
	Btree *b = (*tree)->right;
	a->right = b->left;
	b->left = a;
	(*tree) = b;

}

//右旋
void SigleRightCir(Btree **tree){
	Btree *a = *tree;
	Btree *b = (*tree)->left;
	a->left = b->right;
	b->right = a;
	(*tree) = b;

}

//右左旋
void RightLeftCir(Btree **tree){
	SigleRightCir(&(*tree)->right);
	SigleLeftCir(tree);

}

//左右旋
void LeftRightCir(Btree **tree){
	SigleLeftCir(&(*tree)->left);
	SigleRightCir(tree);

}

//插入

Btree *BalanceTreeInsert(Btree **tree, ElementType x){
	if ((*tree) == NULL){
		(*tree) = CreateNode(x);
	}
	else{
		if ((*tree)->data < x){
			
			(*tree)->right = BalanceTreeInsert(&(*tree)->right, x);
			
			if (GetHight((*tree)->left) - GetHight((*tree)->right) == -2){
				if ((*tree)->right->data < x){
					SigleLeftCir((tree));
				}
				else{
					RightLeftCir(tree);
				}
			}
		}
		else if ((*tree)->data>x){
			(*tree)->left = BalanceTreeInsert(&(*tree)->left, x);

			if (GetHight((*tree)->left) - GetHight((*tree)->right) == 2){
				if ((*tree)->data < x){
					SigleRightCir(tree);
				}
				else{
					LeftRightCir(tree);
				}
			}
		}
		else{
			printf("已存在\n");
			exit(-1);
		}
	}
	return *tree;


}


Btree *Getmax(Btree *tree){
	while (tree->right){
		tree = tree->right;
	}
	return tree;
}
//删除
Btree *BalanceTreeDelet(Btree **tree, ElementType x){
	if ((*tree) == NULL){
		printf("不存在\n");
		exit(-1);
	}
	if ((*tree)->data < x){
		//递归返回为右子树,说明删完了
		(*tree)->right = BalanceTreeDelet(&(*tree)->right, x);
		//判断,该结点平衡因子是否被破坏
		if (GetHight((*tree)->left) - GetHight((*tree)->right) == 2){
			//如果被破坏,左孩子结点
			if (GetHight((*tree)->left->left) - GetHight((*tree)->left->right) == 1){
				SigleRightCir(tree);
			}
			else{
				LeftRightCir(tree);
			}
		}


	}
	else if ((*tree)->data > x){
		//递归返回为左子树
		(*tree)->left = BalanceTreeDelet(&(*tree)->left, x);
		//判断,该结点是否被破坏
		if (GetHight((*tree)->left) - GetHight((*tree)->right) == -2){
			//右孩子结点
			if (GetHight((*tree)->right->left) - GetHight((*tree)->right->right) == -1){
				SigleLeftCir(tree);
			}
			else{
				RightLeftCir(tree);
			}
		}

	}
	//找到
	else{
		if ((*tree)->left && (*tree)->right){
			Btree *temp = Getmax((*tree)->left);
			int x = temp->data;
			(*tree)->data = x;
			(*tree)->left = BalanceTreeDelet(&(*tree)->left, x);
			//这里也需要调整
			if (GetHight((*tree)->left) - GetHight((*tree)->right) == -2){
				//左孩子结点
				if (GetHight((*tree)->right->left) - GetHight((*tree)->right->right) == -1){
					SigleLeftCir(tree);
				}
				else{
					RightLeftCir(tree);
				}
			}

		}
		else if ((*tree)->left == NULL && (*tree)->right){
			Btree *temp = *tree;
			*tree = (*tree)->right;
			free(temp);

		}
		else if ((*tree)->left && (*tree)->right  == NULL){
			Btree *temp = *tree;
			*tree = (*tree)->left;
			free(temp);

		}
		else{
			Btree *temp = *tree;
			*tree = NULL;
			free(temp);
		}
	}
	return *tree;
}



int main(){
	Btree *root = NULL;
	BalanceTreeInsert(&root, 6);
	BalanceTreeInsert(&root, 4);
	BalanceTreeInsert(&root, 9);
	BalanceTreeInsert(&root, 2);
	BalanceTreeInsert(&root, 3);
	BalanceTreeInsert(&root, 5);
	BalanceTreeInsert(&root, 10);
	BalanceTreeInsert(&root, 8);


	BalanceTreeDelet(&root, 6);
	return 0;
}

  • 16
    点赞
  • 130
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值