📅  最后修改于: 2023-12-03 15:14:37.603000             🧑  作者: Mango
二叉搜索树是一种经典的数据结构,它有着很多的应用场景。在本章中,我们将学习如何使用 JavaScript 来实现一个二叉搜索树,并在 Hackerrank 平台上完成一道关于二叉搜索树的练习题。
二叉搜索树(Binary Search Tree,简称 BST)是一种有序树,它将所有的值存储在树的节点中,并且满足以下性质:
下面是一个例子:
4
/ \
2 6
/ \ / \
1 3 5 7
这个二叉搜索树有以下特点:
首先,我们需要定义二叉搜索树中的节点。每个节点包含三个属性:值、左子节点和右子节点。
class Node {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
}
接下来,我们需要实现插入节点的方法,它用来向二叉搜索树中添加新的节点。
class BinaryTree {
constructor() {
this.root = null;
}
insert(value) {
const newNode = new Node(value);
if (!this.root) {
this.root = newNode;
return;
}
let current = this.root;
while (true) {
if (value < current.value) {
if (!current.left) {
current.left = newNode;
break;
}
current = current.left;
} else if (value > current.value) {
if (!current.right) {
current.right = newNode;
break;
}
current = current.right;
} else {
// 如果值已存在,则不执行任何操作
break;
}
}
}
}
在这个方法中,首先创建一个新的节点。如果树为空,那么将节点设置为根节点并返回;否则,从根节点开始遍历树,直到找到一个合适的位置。
如果要插入的值小于当前节点的值,则向左子树移动;如果要插入的值大于当前节点的值,则向右子树移动。如果要插入的值已经存在于树中,则不执行任何操作。
查找节点是二叉搜索树的一个重要操作。以下是查找节点的方法:
class BinaryTree {
// ...
find(value) {
let current = this.root;
while (current) {
if (value === current.value) {
return current;
} else if (value < current.value) {
current = current.left;
} else if (value > current.value) {
current = current.right;
}
}
return null;
}
}
在这个方法中,从根节点开始遍历树,如果要查找的值等于当前节点的值,则返回当前节点。如果要查找的值小于当前节点的值,则向左子树移动;如果要查找的值大于当前节点的值,则向右子树移动。如果找不到包含要查找的值的节点,则返回 null。
删除节点是编写二叉搜索树代码的最难部分之一。以下是删除节点的方法:
class BinaryTree {
// ...
delete(value) {
this.root = this._deleteNode(this.root, value);
}
_deleteNode(current, value) {
if (!current) {
return null;
}
if (value === current.value) {
if (!current.left && !current.right) {
return null;
} else if (!current.left) {
return current.right;
} else if (!current.right) {
return current.left;
} else {
// 左右子树都存在,需要找到左子树中最大的节点或右子树中最小的节点
let maxLeft = current.left;
while (maxLeft.right) {
maxLeft = maxLeft.right;
}
current.value = maxLeft.value;
current.left = this._deleteNode(current.left, maxLeft.value);
}
} else if (value < current.value) {
current.left = this._deleteNode(current.left, value);
} else if (value > current.value) {
current.right = this._deleteNode(current.right, value);
}
return current;
}
}
在这个方法中,我们使用递归来删除节点。首先检查当前节点是否存在。如果要删除的值等于当前节点的值,则有以下几种情况:
如果要删除的值小于当前节点的值,则向左子树移动;如果要删除的值大于当前节点的值,则向右子树移动。
在接下来的练习中,我们需要实现后序遍历二叉搜索树。以下是后序遍历的代码:
class BinaryTree {
// ...
_postorderTraversal(node, output) {
if (!node) {
return;
}
this._postorderTraversal(node.left, output);
this._postorderTraversal(node.right, output);
output.push(node.value);
}
postorderTraversal() {
const output = [];
this._postorderTraversal(this.root, output);
return output;
}
}
在这个方法中,我们使用递归来后序遍历二叉搜索树。首先遍历左子树,然后遍历右子树,最后将当前节点的值加入到输出数组中。
在 Hackerrank 上,我们需要完成一个关于二叉搜索树的一个练习题。在这个练习中,我们需要输入一个数组,然后将其插入到一个二叉搜索树中。最后,我们需要后序遍历这个二叉搜索树,并将遍历结果输出。
以下是完整的解决方案:
class Node {
constructor(value) {
this.value = value;
this.left = null;
this.right = null;
}
}
class BinaryTree {
constructor() {
this.root = null;
}
insert(value) {
const newNode = new Node(value);
if (!this.root) {
this.root = newNode;
return;
}
let current = this.root;
while (true) {
if (value < current.value) {
if (!current.left) {
current.left = newNode;
break;
}
current = current.left;
} else if (value > current.value) {
if (!current.right) {
current.right = newNode;
break;
}
current = current.right;
} else {
break;
}
}
}
_postorderTraversal(node, output) {
if (!node) {
return;
}
this._postorderTraversal(node.left, output);
this._postorderTraversal(node.right, output);
output.push(node.value);
}
postorderTraversal() {
const output = [];
this._postorderTraversal(this.root, output);
return output;
}
}
function processData(input) {
// 解析输入
const lines = input.trim().split('\n');
const n = parseInt(lines[0]);
const a = lines[1].split(' ').map(x => parseInt(x));
// 创建二叉搜索树并插入元素
const bst = new BinaryTree();
for (let i = 0; i < n; i++) {
bst.insert(a[i]);
}
// 后序遍历并输出结果
const result = bst.postorderTraversal();
console.log(result.join(' '));
}
在这个解决方案中,我们首先输入一个数组并将其解析为一个整数数组。然后,我们创建一个新的二叉搜索树并将每个元素插入树中。最后,我们实现了一个后序遍历的函数来遍历树并将值添加到输出数组中。最后,我们将输出数组的元素连接成一个字符串,并将其输出。
在本章中,我们学习了二叉搜索树的定义、插入、查找、删除和遍历节点。我们还提供了一个完整的解决方案,用于在 Hackerrank 平台上完成关于二叉搜索树的一个练习题。