品味C++实现AVL树的删除操作

最近在写数据结构课设,基于字典树,avl树,pat树(压缩字典树),哈希表写个英汉词典

写完后会开源, 可以期待一波

分享一些饶有趣味的感悟hhh


AVL树的删除操作要虽比插入复杂一点,不过思想很值得揣摩

抛开细节,如果真的找到了那个要删除的节点,问题就转化为,如何使删除完的树继续平衡呢,利用二叉排序树的特点——左子树比根小,右子树比根大  , 找到左子树中的最大值或者右子树中的最小值来替换他, 因为在局部子树的最值节点,都是在边缘地带,牵扯的鸡毛蒜皮之事都远小于拖家带口的节点

❓那么, 该选左子树中的最大值还是右子树中的最小值呢?随便都可以吗

答案是否定的, 不要因小失大, 小——删除一个节点;大——整棵自平衡二叉查找树的平衡性

我们可以将情况进一步细化

  • 若该节点同时有左右子树.  那样我们就需要比较它左右子树的高度,选择高的那一方,取其最大/最小节点进行替代, 同时向下递归, 在左子树/右子树中删除那个最大/最小节点, 很奇妙, 一次简单的选择具有"柳暗花明又一村"的效果
  • 若该节点至少一棵子树为空, 我们就可以直接用其左子树.右子树的根来替代

另一方面,如果当前没找到那个要删除的节点, 就需要根据与目标的大小相比较,进而选择左/右子树走下去(递归实现), 当回溯回来的时候,可能已经按上面的那种情况实现了删除, 那样就需要判断是否失衡, 此刻的左右子树高度差是否为二(即失衡), 接下来的问题就回归到树的旋转上去了,上一篇博文有所提及

C++实现AVL树的四种旋转_☆迷茫狗子的秘密基地☆-CSDN博客结构template<typename T>struct AVLNode{ T data; int height; AVLNode* lchild, *rchild; AVLNode(T dt, AVLNode* l, AVLNode* r):data(dt),lchild(l),rchild(r){}};template<typename T>class AVLTree{ public: AVLTree()..https://blog.csdn.net/qq_39391544/article/details/121688941?spm=1001.2014.3001.5501

AVLNode<PII>* AVLTree::MaxNode(AVLNode<PII>* pRoot)
{
	if(pRoot == nullptr) return nullptr;
	while(pRoot->rchild != nullptr)
	{
		pRoot = pRoot->rchild;
	}
	return pRoot;
}

AVLNode<PII>* AVLTree::MinNode(AVLNode<PII>* pRoot)
{
	if(pRoot == nullptr) return nullptr;
	while(pRoot->lchild != nullptr)
	{
		pRoot = pRoot->lchild;
	}
	return pRoot;
}

void AVLTree::DeleteWord(string word)
{
	root = _deleteWord(root, word);
}

AVLNode<PII>* AVLTree::_deleteWord(AVLNode<PII>* pRoot, string word)
{
	if(pRoot == nullptr){
		//cout << "不存在" << word << endl;
		return nullptr;
	}

	//找到对应值 
	if(pRoot->data.first == word)
	{
		// 如果同时存在左右子树,则根据高度选择更换左子树最大节点或右子树最小节点
		if(pRoot->lchild != nullptr && pRoot->rchild != nullptr)
		{
			if(GetH(pRoot->lchild) > GetH(pRoot->rchild))
			{
				
				AVLNode<PII>* left_max = MaxNode(pRoot->lchild);			// 用左子树的最大节点替代当前节点
				
				pRoot->data = left_max->data;				// 当前分支情况left_max不可能为nullptr,可以直接覆盖data 
				
				pRoot->lchild =  _deleteWord(pRoot->lchild, left_max->data.first);	// 转移矛盾为删除左子树的最大节点
				
			}else{
				
				AVLNode<PII>* right_min = MinNode(pRoot->rchild);			// 用右子树的最小节点替代当前节点
				
				pRoot->data = right_min->data;	// 当前分支情况right_min不可能为nullptr,可以直接覆盖data 
				
				pRoot->lchild =  _deleteWord(pRoot->lchild, right_min->data.first);	// 转移矛盾为删除左子树的最大节点
			}
		}
		// 至少一个子树为空 
		else{
			AVLNode<PII>* p = pRoot;
			if(pRoot->lchild != nullptr)
				pRoot = pRoot->lchild;
			else if(pRoot->rchild != nullptr)
				pRoot = pRoot->rchild;
				
			delete p;
			cout << "成功删除" << word << endl;
			return nullptr;
		}
		
	}
	else if(pRoot->data.first > word)
	{
		pRoot->lchild = _deleteWord(pRoot->lchild, word);
		// 若是处理左子树完后失衡,则对右子树进行旋转变换 
		if(GetH(pRoot->rchild) - GetH(pRoot->lchild) == 2)
		{
			if(GetH(pRoot->rchild->lchild) > GetH(pRoot->rchild->rchild))
				pRoot = RL_Rotation(pRoot);
			else
				pRoot = Left_Rotation(pRoot);
		}
	}
	else if(pRoot->data.first < word)
	{
		pRoot->rchild = _deleteWord(pRoot->rchild, word);
		// 若是处理右子树完后失衡,则对左子树进行旋转变换
		if(GetH(pRoot->lchild) - GetH(pRoot->rchild) == 2)
		{
			if(GetH(pRoot->lchild->rchild) > GetH(pRoot->lchild->lchild))
				pRoot = LR_Rotation(pRoot);
			else 
				pRoot = Right_Rotation(pRoot);
		}
	}
	
	return pRoot;
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
AVL树的插入和删除操作都需要对树进行旋转操作来保持AVL树的平衡性。下面是C语言实现AVL树插入和删除操作AVL树插入操作: ```c // AVL树节点定义 struct AVLNode { int key; int height; struct AVLNode* left; struct AVLNode* right; }; // 计算节点高度 int height(struct AVLNode* node) { if (node == NULL) { return 0; } return node->height; } // 右旋操作 struct AVLNode* rotate_right(struct AVLNode* y) { struct AVLNode* x = y->left; struct AVLNode* t2 = x->right; // 执行旋转 x->right = y; y->left = t2; // 更新高度 y->height = max(height(y->left), height(y->right)) + 1; x->height = max(height(x->left), height(x->right)) + 1; return x; } // 左旋操作 struct AVLNode* rotate_left(struct AVLNode* x) { struct AVLNode* y = x->right; struct AVLNode* t2 = y->left; // 执行旋转 y->left = x; x->right = t2; // 更新高度 x->height = max(height(x->left), height(x->right)) + 1; y->height = max(height(y->left), height(y->right)) + 1; return y; } // 计算平衡因子 int balance_factor(struct AVLNode* node) { if (node == NULL) { return 0; } return height(node->left) - height(node->right); } // 插入节点 struct AVLNode* avl_insert(struct AVLNode* node, int key) { // 执行BST插入 if (node == NULL) { struct AVLNode* new_node = (struct AVLNode*)malloc(sizeof(struct AVLNode)); new_node->key = key; new_node->height = 1; new_node->left = NULL; new_node->right = NULL; return new_node; } if (key < node->key) { node->left = avl_insert(node->left, key); } else if (key > node->key) { node->right = avl_insert(node->right, key); } else { // key已经存在,不需要插入 return node; } // 更新高度 node->height = max(height(node->left), height(node->right)) + 1; // 计算平衡因子 int bf = balance_factor(node); // 如果平衡因子大于1,需要进行旋转操作 if (bf > 1) { if (key < node->left->key) { // 左左情况,执行右旋操作 return rotate_right(node); } else { // 左右情况,先对左子树进行左旋操作,再对根节点进行右旋操作 node->left = rotate_left(node->left); return rotate_right(node); } } else if (bf < -1) { if (key > node->right->key) { // 右右情况,执行左旋操作 return rotate_left(node); } else { // 右左情况,先对右子树进行右旋操作,再对根节点进行左旋操作 node->right = rotate_right(node->right); return rotate_left(node); } } return node; } ``` AVL树删除操作: ```c // 查找最小值节点 struct AVLNode* find_min(struct AVLNode* node) { if (node == NULL) { return NULL; } if (node->left == NULL) { return node; } return find_min(node->left); } // 删除节点 struct AVLNode* avl_delete(struct AVLNode* node, int key) { // 执行BST删除 if (node == NULL) { return NULL; } if (key < node->key) { node->left = avl_delete(node->left, key); } else if (key > node->key) { node->right = avl_delete(node->right, key); } else { if (node->left == NULL || node->right == NULL) { // 被删除节点只有一个子节点或者没有子节点 struct AVLNode* temp = node->left ? node->left : node->right; if (temp == NULL) { // 没有子节点,直接删除 temp = node; node = NULL; } else { // 有一个子节点,用子节点替换被删除节点 *node = *temp; } free(temp); } else { // 被删除节点有两个子节点,找到右子树的最小值节点替换被删除节点 struct AVLNode* temp = find_min(node->right); node->key = temp->key; node->right = avl_delete(node->right, temp->key); } } if (node == NULL) { return NULL; } // 更新高度 node->height = max(height(node->left), height(node->right)) + 1; // 计算平衡因子 int bf = balance_factor(node); // 如果平衡因子大于1,需要进行旋转操作 if (bf > 1) { if (balance_factor(node->left) >= 0) { // 左左情况,执行右旋操作 return rotate_right(node); } else { // 左右情况,先对左子树进行左旋操作,再对根节点进行右旋操作 node->left = rotate_left(node->left); return rotate_right(node); } } else if (bf < -1) { if (balance_factor(node->right) <= 0) { // 右右情况,执行左旋操作 return rotate_left(node); } else { // 右左情况,先对右子树进行右旋操作,再对根节点进行左旋操作 node->right = rotate_right(node->right); return rotate_left(node); } } return node; } ``` 以上是AVL树的插入和删除操作的C语言实现。需要注意的是,AVL树的插入和删除操作都需要对树进行旋转操作来保持平衡,因此这些操作的时间复杂度是O(log n)。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

泥烟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值