🥳每日一练-平衡二叉树节点的删除-JS简易版

上篇文章分享了平衡二叉树的构建,这篇文章来分享平衡二叉树节点的删除

平衡二叉树,在王道考研里面,讲得很详细,并且罗列了很多种情况

  1. 删除叶子
  2. 删除只有一个子树
  3. 删除有两个子树

井且详细讲解了删除节点之后的操作:

  1. 首先向上查找。查找不平衡的节点
  2. 如果有,就往下寻找高度最高的儿子,和高度最高的的孙子
  3. 找到之后,就可以确定用哪种旋转方式(LL、RR、RL、LR),让不平衡的节点回复平衡
  4. 继续往上找,重复1-3的步骤。 直到找到根节点,就停止寻找

每删除一个节点,都要经历上述的查找过程。具体讲解过程可以看视频讲解: 7.3_3_平衡二叉树的删除

其实这段内容讲得有些复杂,会给代码的编写带来困扰。讲复杂的地方,主要是在上面第二点 A:找儿子和孙子就是为了确定使用那种旋转方式。其实不用按照这里逻辑,只要判断左右子树的高度差就可以了。

光说不练假把式,来看看如何用代码来实现

首先需要用到上篇文章分享地基础代码

🥳每日一练-平衡二叉树的构建-JS简易版 - 掘金

javascript 复制代码
class AVLTree {
	constructor() {
		this.root = null;
	}

	getHeight(node) {
		if (!node) return 0;
		return node.height;
	}

	updateHeight(node) {
		node.height = 1 + Math.max(this.getHeight(node.left), this.getHeight(node.right));
	}

	getBalance(node) {
		return this.getHeight(node.left) - this.getHeight(node.right);
	}

	leftRotate(node) {
		let newRoot = node.right;
		node.right = newRoot.left;
		newRoot.left = node;

		this.updateHeight(node);
		this.updateHeight(newRoot);

		return newRoot;
	}

	rightRotate(node) {
		let newRoot = node.left;
		node.left = newRoot.right;
		newRoot.right = node;

		this.updateHeight(node);
		this.updateHeight(newRoot);

		return newRoot;
	}

	balance(node) {
		if (this.getBalance(node) > 1) {
			if (this.getBalance(node.left) < 0) {
				node.left = this.leftRotate(node.left);
			}
			return this.rightRotate(node);
		} else if (this.getBalance(node) < -1) {
			if (this.getBalance(node.right) > 0) {
				node.right = this.rightRotate(node.right);
			}
			return this.leftRotate(node);
		}
		return node;
	}

	insert(value) {
		this.root = this._insert(this.root, value);
	}

	_insert(node, value) {
		if (!node) return new Node(value);

		if (value < node.value) {
			node.left = this._insert(node.left, value);
		} else if (value > node.value) {
			node.right = this._insert(node.right, value);
		} else {
			return node;
		}

		this.updateHeight(node);
		return this.balance(node);
	}
}

然后只需要在这个基础代码上添加删除方法就好了

javascript 复制代码
	delete(value) {
		this.root = this._delete(this.root, value);
	}

	_delete(node, value) {
		if (!node) return null;
		if (value < node.value) {
			node.left = this._delete(node.left, value);
		} else if (value > node.value) {
			node.right = this._delete(node.right, value);
		} else {
			if (!node.left) return node.right;
			if (!node.right) return node.left;

			let minNode = node.right;
			while (minNode.left) minNode = minNode.left;

			node.right = this._delete(node.right, minNode.value);

			minNode.left = node.left;
			minNode.right = node.right;

			node = minNode;
		}
		this.updateHeight(node);
		return this.balance(node);
	}

删除的逻辑和二叉排序树的逻辑一致,只多了最后两行,一个this.updateHeight(node)是更新当前节点的高度,第二个this.balance(node)是检查当前节点是否因为删除导致不平衡,如果导致了不平衡,就使用旋转操作,使该节点重新到达平衡。

排序二叉树的删除逻辑详细解释,可以看这篇文章: 🥳每日一练-二叉排序树的节点删除-JS简易版 - 掘金

并且_delete是递归调用,所以天然地就实现了由子即父地检查节点是否平衡。

为什么这里使用两个 delete 方法。因为这样可以实现删除树的根节点。相当 nice 了

终于直到王道为什么不提供平衡二叉树的代码了,因为需要用到面向对象的知识,才能比较简单地表达出来。如果不面向对象,那代码会很复杂,而且考研也不考,就不增加大家负担了是这样吧哈哈?

测试一下:

js 复制代码
let tree = new AVLTree();
let arr = [4, 2, 7, 1, 3, 6, 9];

arr.forEach((value) => tree.insert(value));
const root = tree;

const printNode = (tree) => {
	if (!tree) return null;
	printNode(tree.left);
	console.log(tree.value, root.getBalance(tree));
	printNode(tree.right);
};

printNode(tree.root);
// 1 0
// 2 0
// 3 0
// 4 0
// 6 0
// 7 0
// 9 0

printNode不仅中序遍历输出节点的值,还会输出节点的 balance 值。可以看到每个节点都是平衡的。

js 复制代码
tree.delete(7);
printNode(tree.root);
// 1 0
// 2 0
// 3 0
// 4 0
// 6 0
// 9 1

tree.delete(4);
printNode(tree.root);
// 1 0
// 2 0
// 3 0
// 6 1
// 9 0

删除节点之后,各个节点仍然是平衡的

总结

这篇文章分享了平衡二叉树的节点删除如何用 JS 代码来实现,如果明白了之前两篇内容的分享,这篇文章也就很容易理解了

你觉得这篇文章怎么样?喜欢就点赞+关注吧

相关推荐
名字还没想好☜8 小时前
React 实现暗黑模式切换:localStorage 持久化、SSR 首屏闪烁与跟随系统主题
前端·javascript·react.js·ecmascript·react·next.js
find1star8 小时前
LeetCode 141:环形链表
java·算法·leetcode·链表
迅翼SwiftWing9 小时前
编队系列(总)|固定翼编队如何实现稳定飞行?通信架构、协同算法与工程约束深度解析
算法·架构
自动化监测Learner9 小时前
主流 Web 端地图引擎对比:选型指南与优劣分析
javascript
LB21129 小时前
力扣160 21 86
算法·leetcode·职场和发展
小智老师PMP10 小时前
2026深度解析|PMP第八版与NPDP核心侧重点本质区别(管理类证书怎么选)
开发语言·分布式·算法·职场和发展·产品经理
HugoStudio_SWAN10 小时前
洛谷 B4450 / B3867 / B3923 智慧购物、储蓄与做题——从程序到生活
c++·学习·程序人生·算法·生活
a1879272183110 小时前
【算法】动态规划第二篇:双序列 DP 三课——继承、计步与断链
算法·leetcode·动态规划·dp·回溯·暴力·算法讲解
江畔柳前堤11 小时前
前台·中台·后台:2026年AI原生时代的架构全景图
开发语言·人工智能·算法·机器学习·架构·scala·ai-native
文心快码BaiduComate12 小时前
2026 OPC x AI Coding 趋势案例交流会圆满落幕:一个人就一支研发团队
算法