版权声明:本文为博主原创文章,欢迎转载,转载请注明作者、原文超链接 https://blog.csdn.net/qq_40109752/article/details/83088322
知识点
- 二叉查找树,也称二叉搜索树、有序二叉树(英语:ordered binary tree)是指一棵空树
- 任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
- 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
- 任意节点的左、右子树也分别为二叉查找树;
- 没有键值相等的节点;
- 二叉查找树相比于其他数据结构的优势在于查找、插入的时间复杂度较低。为O(log n)。
- 二叉查找树是基础性数据结构,用于构建更为抽象的数据结构,如集合、multiset、关联数组等。
实现代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>二叉查找树</title>
</head>
<body>
<script>
// 单个节点对象
class Node {
constructor (data, left, right) {
this.data = data;
this.left = left;
this.right = right;
}
}
// 树
class BinarySearchTree {
constructor () {
this.root = null;
}
// 插入成功返回树
insert (data) {
let cNode = new Node(data, null, null);
// 空树
if (!this.root) {
this.root = cNode;
return ;
}
// 非空树
let currentNode = this.root;
let parent = null;
// 遍历
while(1) {
// 得到一个指向 即将改变 或 其子节点将要被改变 的节点的 变量
parent = currentNode;
// 左子树
if (data < currentNode.data) {
// currentNode 指向为空,赋值到currentNode无效
/* currentNode = parent.left;
if (currentNode === null) {
currentNode = n;
break;
}*/
currentNode = currentNode.left;
if (currentNode === null) {
parent.left = cNode;
break
}
}
// 右子树
else if ( data > currentNode.data ) {
// currentNode 指向为空,赋值到currentNode无效
/*currentNode = parent.right;
if (currentNode === null) {
currentNode = n;
break;
}*/
currentNode = currentNode.right;
if (currentNode === null) {
parent.right = cNode;
break;
}
}
// 相等
else {
break;
}
}
}
// 传入数组,创建树
create (arr) {
if (!arr.length) {
this.root = null;
}else {
let length = arr.length;
for (let i = 0; i < length; i++) {
console.log()
this.insert(arr[i]);
}
}
}
// 删除
remove (data) {
this.root = this.removeNodeByData(this.root, data);
}
// 返回删除对应值后的 "node"
removeNodeByData (node, data) {
if (node === null) {
return null;
}
// 数据等于传入树的根节点数据
if (data === node.data) {
// 子节点都为空
if (node.left === null && node.right === null) {
// 返回为空 树为空
return null;
}
// 左节点为空
if (node.left === null){
// 删除的数据等于根节点的数据,且根节点左节点为空,删除根节点,返回右节点
return node.right
}
// 右节点为空
if (node.right === null){
return node.left;
}
// 思路:子节点都不为空的处理函数,找到删除节点的中序遍历的直接前驱(或直接后驱)结点,用该结点来替换要删除的节点,再删除该节点
// 得到直接的后驱节点(节点的右子树最左边的节点,或最右边的节点)
let getAftNode = function (node) {
if (node.left === null && node.right === null) {
return node;
}
if (node.left !== null) {
return getAftNode(node.left);
}
if (node.right !== null) {
return node.right;
}
}
//相等,且左右节点都不为空
let tempNode = getAftNode(node.right);
// 要删除的节点的值等于 其直接后继的值
node.data = tempNode.data;
// 删除 要删除的节点 的直接后继
node.right = this.removeNodeByData(node.right, tempNode.data);
/* {
// 得到直接的前驱节点(节点的左子树最右边的节点,或最左边的节点)
let getPreNode = function (node) {
if (node.left === null && node.right === null) {
return node
}
if (node.right !== null) {
return getPreNode(node.right)
}
if (node.left !== null) {
return node.left
}
}
let tempNode = getPreNode(node.left);
node.data = tempNode.data;
node.left = this.removeNodeByData(node.left, tempNode.data);
}*/
return node;
}
else if (data < node.data) {
node.left = this.removeNodeByData(node.left, data);
// 当前的节点不变
return node;
}else {
node.right = this.removeNodeByData(node.right, data);
// 当前的节点不变
return node
}
}
// 非递归查找, 返回查找到的节点
findByNonRecur(data) {
let current = this.root;
let tagNode = null;
while (current !== null) {
console.log(current);
if (data === current.data) {
tagNode = current;
break;
}else if (data < current.data) {
current = current.left;
} else if (data > current.data) {
current = current.right;
}
}
// 查找到返回节点,没查找返回null
return tagNode
}
// 递归查找,返回节点
findByRecur (data) {
// let current = node||this.root; --- 造成无限循环
let current = this.root;
return (function _selfCall(data, current) {
if (current === null) {
return null;
}
if (current.data === data) {
return current
}else if (data < current.data) {
current = current.left;
// 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
// return arguments.callee(data, current)
return _selfCall(data, current)
} else {
current = current.right;
// 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
// return arguments.callee(data, current)
return _selfCall(data, current)
}
})(data, current)
}
// 获取最大值
findMax(){
let current = this.root;
while(current.right !== null) {
current = current.right;
}
return current.data
}
// 获取最小值
findMin(){
let current = this.root;
while(current.left!==null){
current = current.left
}
return current.data
}
// 先序遍历 -- 根、左、右
preTravel(node){
let preTravelArr = [];
(function _preTravel (node) {
if (node !== null) {
preTravelArr.push(node.data);
_preTravel(node.left);
_preTravel(node.right);
}
})(node)
return preTravelArr;
}
// 中序遍历 -- 左、根、右
midTravel(node){
let midTravelArr = [];
(function _midTravel (node) {
if (node !== null) {
_midTravel(node.left);
midTravelArr.push(node.data);
_midTravel(node.right);
}
})(node)
return midTravelArr;
}
// 后序遍历 -- 左、右、根
aftTravel(node){
let aftTravelArr = [];
(function _aftTravel (node) {
if (node !== null) {
_aftTravel(node.left);
_aftTravel(node.right);
aftTravelArr.push(node.data);
}
})(node)
return aftTravelArr;
}
}
let BSTree = new BinarySearchTree();
// 创建树
BSTree.create([62,58,47,35,29,37,36,51,49,48,50,56,88,73,99,93]);
// 操作
</script>
</body>
</html>