JavaScript 实现二叉排序树
使用 JavaScript 实现二叉排序树的节点定义、插入、删除、查找等基本操作
问题
用 JavaScript 实现二叉排序树的定义和基本操作。
解答
什么是二叉排序树
二叉排序树是一种特殊的二叉树,具有以下性质:
- 若左子树不空,则左子树上所有节点的值均小于根节点的值
- 若右子树不空,则右子树上所有节点的值均大于根节点的值
- 左、右子树也分别为二叉排序树
- 没有键值相等的节点
节点定义
使用链式存储结构,每个节点包含数据域、左指针域、右指针域和计数器:
class Node {
constructor(data, left, right) {
this.data = data;
this.left = left;
this.right = right;
this.count = 1; // 用于统计相同值的出现次数
}
}
二叉排序树类
class BSTree {
constructor() {
this.root = null;
}
// 插入节点
insert(data) {
let newNode = new Node(data, null, null);
if (this.root == null) {
this.root = newNode;
} else {
let currNode = this.root;
let parentNode = null;
while (true) {
parentNode = currNode;
if (newNode.data < currNode.data) {
currNode = currNode.left;
if (!currNode) {
parentNode.left = newNode;
break;
}
} else if (newNode.data > currNode.data) {
currNode = currNode.right;
if (!currNode) {
parentNode.right = newNode;
break;
}
} else {
// 值相同时,计数器加1
currNode.count++;
break;
}
}
}
}
// 查找节点
find(data) {
let currNode = this.root;
while (currNode) {
if (data === currNode.data) {
return currNode;
} else if (data < currNode.data) {
currNode = currNode.left;
} else {
currNode = currNode.right;
}
}
return null;
}
// 获取最小值节点
getMinNode(node = this.root) {
let currNode = node;
while (currNode.left) {
currNode = currNode.left;
}
return currNode;
}
// 获取最大值节点
getMaxNode(node = this.root) {
let currNode = node;
while (currNode.right) {
currNode = currNode.right;
}
return currNode;
}
// 删除节点
remove(data) {
this.root = this._removeNode(this.root, data);
}
_removeNode(node, data) {
if (node == null) {
return null;
}
if (data === node.data) {
// 情况1:叶子节点
if (node.left == null && node.right == null) {
return null;
}
// 情况2:没有左子节点
if (node.left == null) {
return node.right;
}
// 情况3:没有右子节点
if (node.right == null) {
return node.left;
}
// 情况4:左右子节点都存在
// 找到右子树的最小值节点
let tempNode = this.getMinNode(node.right);
node.data = tempNode.data;
node.count = tempNode.count;
node.right = this._removeNode(node.right, tempNode.data);
return node;
} else if (data < node.data) {
node.left = this._removeNode(node.left, data);
return node;
} else {
node.right = this._removeNode(node.right, data);
return node;
}
}
}
测试示例
let myTree = new BSTree();
myTree.insert(20);
myTree.insert(10);
myTree.insert(30);
myTree.insert(7);
myTree.insert(9);
myTree.insert(15);
myTree.insert(42);
myTree.insert(57);
// 获取最大值
console.log(myTree.getMaxNode()); // Node {data: 57, ...}
// 获取最小值
console.log(myTree.getMinNode()); // Node {data: 7, ...}
// 删除节点
myTree.remove(7);
console.log(myTree.getMinNode()); // Node {data: 9, ...}
myTree.remove(42);
console.log(myTree.getMaxNode()); // Node {data: 57, ...}
关键点
- 二叉排序树的插入操作通过比较节点值,小于当前节点则向左子树查找,大于则向右子树查找,直到找到空位置插入
- 查找最小值只需沿着左子树一直向下,查找最大值则沿着右子树向下
- 删除节点分三种情况:叶子节点直接删除,只有一个子节点则用子节点替代,有两个子节点则用右子树的最小值替代
- 使用 count 属性可以记录相同值的出现次数,避免插入重复节点
- 删除操作使用递归实现,代码更简洁清晰
目录