这篇文章还是来点简单的:判断一颗树是否为平衡二叉树
平衡二叉树的性质是左右子树的高度差不超过 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 树的函数。其中步骤就是我开头提到的:
- 先判断左右子树是否为平衡二叉树,如果不是,那整个树就不是平衡二叉树;如果是就继续下面的判断
- 求解左右子树的高度差,如果不超过 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 文末的代码
你觉得这篇文章怎么样?喜欢就点赞+关注吧