🥳每日一练-判断二叉树是否为AVL-JS简易版

这篇文章还是来点简单的:判断一颗树是否为平衡二叉树

平衡二叉树的性质是左右子树的高度差不超过 2。

因此可以用简单的逻辑来求解今天的练习。

  1. 先判断左右子树是否为平衡二叉树,如果不是,那整个树就不是平衡二叉树;如果是就继续下面的判断
  2. 求解左右子树的高度差,如果不超过 2,那这棵树就是平衡二叉树;否则就不是了

按照这个逻辑就可以写出递归代码

准备数据

先准备一个描述上图的平衡二叉树的数据

javascript 复制代码
class Node {
	constructor(value) {
		this.value = value;
		this.height = 1;
		this.left = null;
		this.right = null;
	}
}

class AVL {
	constructor() {
		this.root = null;
	}
	getHeight(node) {
		if (!node) return 0;
		return node.height;
	}
	updateHeight(node) {
		node.height = Math.max(this.getHeight(node.left), this.getHeight(node.right)) + 1;
	}

	rotateLeft(node) {
		const newRoot = node.right;
		node.right = newRoot.left;
		newRoot.left = node;

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

		return newRoot;
	}

	rotateRight(node) {
		const newRoot = node.left;
		node.left = newRoot.right;
		newRoot.right = node;

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

		return newRoot;
	}

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

	balance(node) {
		if (this.getBalance(node) > 1) {
			if (this.getBalance(node.left) < 0) {
				node.left = this.rotateLeft(node.left);
			}
			return this.rotateRight(node);
		} else if (this.getBalance(node) < -1) {
			if (this.getBalance(node.right) > 0) {
				node.right = this.rotateRight(node.right);
			}
			return this.rotateLeft(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);

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

代码中声明了两个对象。一个描述了节点的属性,另一个描述了创建 AVL 树(平衡二叉树)的各种操作。

代码有些多,具体讲解可以看这篇文章:🥳每日一练-排序二叉树中求解节点层次-JS简易版 - 掘金

创建 AVL

javascript 复制代码
const data = [3, 2, 1, 4, 5, 6, 7, 9, 8];
const avl = new AVL();
data.forEach((item) => {
	avl.insert(item);
});

console.log(avl);

输出看看 avl 的结构是否和图中描述一致:

json 复制代码
{
  root: {
    value: 4,
    height: 4,
    left: {
      value: 2,
      height: 2,
      left: {
        value: 1,
        height: 1,
        left: null,
        right: null,
      },
      right: {
        value: 3,
        height: 1,
        left: null,
        right: null,
      },
    },
    right: {
      value: 6,
      height: 3,
      left: {
        value: 5,
        height: 1,
        left: null,
        right: null,
      },
      right: {
        value: 8,
        height: 2,
        left: {
          value: 7,
          height: 1,
          left: null,
          right: null,
        },
        right: {
          value: 9,
          height: 1,
          left: null,
          right: null,
        },
      },
    },
  },
}

是不是不太好看,看着很不方便,将 json 结构的输出改成树形结构的输出,像下面这样,就很方便了:

这个怎么做到的?

javascript 复制代码
let res = "";
const printTree = (data, deeps = [1]) => {
	let space = deeps
		.slice(0, -1)
		.map((item) => {
			return item == 1 ? "|\t\t" : "\t\t";
		})
		.join("");

	space += "|__";
	res = res + space + (data?.value || "null") + "\n";

	if (!data) return res;
	printTree(data.left, [...deeps, 1]);
	printTree(data.right, [...deeps, 0]);
	return res;
};
console.log(res);

这是将 json 结构树形输出的代码,可以用这个代码输出其他的树,不仅二叉树,多叉树,都可以。

判断是否为 AVL

javascript 复制代码
const judgeAVL = (tree) => {
  if (!tree) return 0;
  
  const leftHeight = judgeAVL(tree.left);
  const rightHeight = judgeAVL(tree.right);
  
  if (leftHeight == -1 || rightHeight == -1) return -1;
  if (Math.abs(leftHeight - rightHeight) > 1) return -1;
  
  return Math.max(leftHeight, rightHeight) + 1;
};

judgeAVL是一个判断是否为 AVL 树的函数。其中步骤就是我开头提到的:

  1. 先判断左右子树是否为平衡二叉树,如果不是,那整个树就不是平衡二叉树;如果是就继续下面的判断
  2. 求解左右子树的高度差,如果不超过 2,那这棵树就是平衡二叉树;否则就不是了

函数接受 tree 的根节点作为参数,并且,如果返回值不为-1,这棵树就是一颗 AVL

测试代码:

javascript 复制代码
console.log(judgeAVL(avl.root)); //4

刚好树的高度是 4 层,没有问题

javascript 复制代码
avl.root.right = null;
console.log(judgeAVL(avl.root)); //-1

将树的的右子树直接删除,这棵树肯定就不是 AVL。测试结果输出了-1,符合预期

完整代码

javascript 复制代码
class Node {
	constructor(value) {
		this.value = value;
		this.height = 1;
		this.left = null;
		this.right = null;
	}
}
class AVL {
	constructor() {
		this.root = null;
	}
	getHeight(node) {
		if (!node) return 0;
		return node.height;
	}
	updateHeight(node) {
		node.height = Math.max(this.getHeight(node.left), this.getHeight(node.right)) + 1;
	}

	rotateLeft(node) {
		const newRoot = node.right;
		node.right = newRoot.left;
		newRoot.left = node;

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

		return newRoot;
	}

	rotateRight(node) {
		const newRoot = node.left;
		node.left = newRoot.right;
		newRoot.right = node;

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

		return newRoot;
	}

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

	balance(node) {
		if (this.getBalance(node) > 1) {
			if (this.getBalance(node.left) < 0) {
				node.left = this.rotateLeft(node.left);
			}
			return this.rotateRight(node);
		} else if (this.getBalance(node) < -1) {
			if (this.getBalance(node.right) > 0) {
				node.right = this.rotateRight(node.right);
			}
			return this.rotateLeft(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);

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

const data = [3, 2, 1, 4, 5, 6, 7, 9, 8];
const avl = new AVL();
data.forEach((item) => {
	avl.insert(item);
});

// 判断是否为平衡二叉树
const judgeAVL = (tree) => {
	if (!tree) return 0;
	const leftHeight = judgeAVL(tree.left);
	const rightHeight = judgeAVL(tree.right);
	if (leftHeight == -1 || rightHeight == -1) return -1;
	if (Math.abs(leftHeight - rightHeight) > 1) return -1;
	return Math.max(leftHeight, rightHeight) + 1;
};
let res = "";
const printTree = (data, deeps = [1]) => {
	let space = deeps
		.slice(0, -1)
		.map((item) => {
			return item == 1 ? "|\t\t" : "\t\t";
		})
		.join("");

	space += "|__";
	res = res + space + (data?.value || "null") + "\n";

	if (!data) return res;
	printTree(data.left, [...deeps, 1]);
	printTree(data.right, [...deeps, 0]);
	return res;
};


console.log(judgeAVL(avl.root));

avl.root.right = null;
printTree(avl.root);
console.log(res);

console.log(judgeAVL(avl.root));

总结:

这篇文章分享了如何判断一颗树是否为平衡二叉树,同时也给出了 JS 代码的实现。读者可以直接 copy 文末的代码

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

相关推荐
她似晚风般温柔78910 分钟前
Uniapp + Vue3 + Vite +Uview + Pinia 分商家实现购物车功能(最新附源码保姆级)
开发语言·javascript·uni-app
Jiaberrr1 小时前
前端实战:使用JS和Canvas实现运算图形验证码(uniapp、微信小程序同样可用)
前端·javascript·vue.js·微信小程序·uni-app
everyStudy2 小时前
JS中判断字符串中是否包含指定字符
开发语言·前端·javascript
luthane2 小时前
python 实现average mean平均数算法
开发语言·python·算法
静心问道2 小时前
WGAN算法
深度学习·算法·机器学习
Ylucius2 小时前
动态语言? 静态语言? ------区别何在?java,js,c,c++,python分给是静态or动态语言?
java·c语言·javascript·c++·python·学习
200不是二百2 小时前
Vuex详解
前端·javascript·vue.js
杰九2 小时前
【算法题】46. 全排列-力扣(LeetCode)
算法·leetcode·深度优先·剪枝
LvManBa2 小时前
Vue学习记录之三(ref全家桶)
javascript·vue.js·学习
manba_2 小时前
leetcode-560. 和为 K 的子数组
数据结构·算法·leetcode