原理
二叉查找树,又称二叉排序树,二叉搜索树。二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
- 若左子树不空,则左子树上所有节点的值均小于它的根节点的值;
- 若右子树不空,则右子树上所有节点的值均大于它的根节点的值;
- 左、右子树也分别为二叉排序树;
- 没有键值相等的节点。
遍历方式:
- 中序:按照节点键值,以升序的方式遍历树所有节点
- 先序:先访问根节点,然后在以同样的方式访问左子树和右子树
- 后序:先访问子节点,从左子树到右子树,最后访问根节点
查找方式:
- 查找给定值
- 查找最小值
- 查找最大值
复杂度:O(logn)
实现
<script>
// 节点对象
class Node {
constructor(data) {
this.root = this;
this.data = data;
this.left = null;
this.right = null;
}
}
// 二叉树
class BinarySearchTree {
constructor() {
this.root = null;
}
/**
* insert 递归插入节点
* @param {[ type ]} data [description]
* @return {[ void ]} [description]
*/
insert(data) {
let newNode = new Node(data);
let insertNode = (node, newNode) => {
if (newNode.data < node.data) {
if (node.left === null) {
node.left = newNode;
} else {
insertNode(node.left, newNode);
}
} else {
if (node.right === null) {
node.right = newNode;
} else {
insertNode(node.right, newNode)
}
}
};
if (!this.root) {
this.root = newNode;
} else {
insertNode(this.root, newNode)
}
}
/* 中序遍历 =>
1.访问左子树(先访问左子树中的左子树,再访问左子树中的右子树);
2.访问根
3.访问右子树(先访问右子树中的左子树,再访问右子树中的右子树)
可以起到排序作用
* [inOrderTraverse 中序遍历]
* @return {[ Array ]} [description]
*/
inOrderTraverse() {
let backs = [];
let inOrderNode = (node, callback) => {
if (node !== null) {
inOrderNode(node.left, callback);
backs.push(callback(node.data));
inOrderNode(node.right, callback);
}
}
let callback = function (v) {
return v
}
inOrderNode(this.root, callback);
return backs
}
/**
* 前序遍历 => 1.访问根节点; 2.访问左子树; 3.访问右子树
* [preOrderTraverse 先序遍历]
* @return {[ Array ]} [description]
*/
preOrderTraverse() {
let backs = [];
let preOrderNode = (node, callback) => {
if (node !== null) {
backs.push(callback(node.data));
preOrderNode(node.left, callback);
preOrderNode(node.right, callback);
}
}
let callback = function (v) {
return v
}
preOrderNode(this.root, callback);
return backs
}
/* 后序遍历 =>
1.访问左子树。(先访问左子树中的左子树,再访问左子树中的右子树)
2.访问右子树。(先访问右子树中的左子树,再访问右子树中的右子树)
3.访问根
*/
postOrderTraverse() {
let backs = [];
const postOrderNode = (node, callback) => {
if (node !== null) {
postOrderNode(node.left, callback);
postOrderNode(node.right, callback);
backs.push(callback(node.data))
}
};
let callback = function (v) {
return v
}
postOrderNode(this.root, callback);
return backs
}
// 查找最小值
getMin(node) {
let minNode = node => {
return node ? (node.left ? minNode(node.left) : node) : null
}
return minNode(node || this.root)
}
// 查找最大值
getMax(node) {
let maxNode = node => {
return node ? (node.right ? maxNode(node.right) : node) : null
}
return maxNode(node || this.root)
}
// 查找特定值
find(data) {
let findNode = (node, data) => {
if (node == null) return false
if (node.data === data) return node;
return findNode((data < node.data) ? node.left : node.right, data);
}
return findNode(this.root, data);
}
// 删除节点
// 返回新的二叉树?
remove(data) {
let removeNode = (node, data) => {
if (node === null) return null;
if (node.data === data) {
if (node.left === null && node.right === null) return null
if (node.left === null) return node.right;
if (node.right === null) return node.left;
if (node.left !== null && node.right !== null) {
let _node = this.getMin(node.right);
node.data = _node.data;
node.right = removeNode(node.right, data);
return node
}
} else if (data < node.data) {
node.left = removeNode(node.left, data);
return node;
} else {
node.right = removeNode(node.right, data);
return node;
}
}
return removeNode(this.root, data)
}
}
</script>
验证
let datas = [11, 7, 5, 3, 6, 9, 8, 10, 20, 14, 12, Tree25, 18];
let bst = new BinarySearchTree();
datas.forEach(data => {
BinarySearchTree.insert(data)
})
console.log(BinarySearchTree.getMax())
console.log(BinarySearchTree.getMin())
console.log(BinarySearchTree)
console.log(BinarySearchTree.remove(20))
console.log(BinarySearchTree)