We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
二叉搜索树(BST,Binary Search Tree),也称为二叉排序树和二叉查找树。
二叉搜索树是一棵二叉树,可以为空。
如果不为空,则满足以下性质:
总结:二叉搜索树的特点主要是较小的值总是保存在左节点上,相对较大的值总是保存在右节点上。这种特点使得二叉搜索树的查询效率非常高,这也就是二叉搜索树中“搜索”的来源。
二叉搜索树有四个最基本的属性:指向节点的根(root),节点中的键(key)、左指针(right)、右指针(right)。
所以,二叉搜索树中除了定义 root 属性外,还应定义一个节点内部类,里面包含每个节点中的 left、right 和 key 三个属性。
// 节点类 class Node { constructor(key) { this.key = key; this.left = null; this.right = null; } }
insert(key)
search(key)
false
preOrderTraverse
inOrderTraverse
postOrderTraverse
min
max
remove(key)
实现思路:
insertNode()
insert(key) 代码实现
// insert(key) 插入数据 insert(key) { const newNode = new Node(key); if (this.root === null) { this.root = newNode; } else { this.insertNode(this.root, newNode); } }
insertNode() 的实现思路:
根据比较传入的两个节点,一直查找新节点适合插入的位置,直到成功插入新节点为止。
当 newNode.key < node.key 向左查找:
情况 1:当 node 无左子节点时,直接插入:
情况 2:当 node 有左子节点时,递归调用 insertNode(),直到遇到无左子节点成功插入 newNode 后,不再符合该情况,也就不再调用 insertNode(),递归停止。
当 newNode.key >= node.key 向右查找,与向左查找类似:
情况 1:当 node 无右子节点时,直接插入:
情况 2:当 node 有右子节点时,依然递归调用 insertNode(),直到遇到传入 insertNode 方法 的 node 无右子节点成功插入 newNode 为止。
insertNode(root, node) 代码实现
insertNode(root, node) { if (node.key < root.key) { // 往左边查找插入 if (root.left === null) { root.left = node; } else { this.insertNode(root.left, node); } } else { // 往右边查找插入 if (root.right === null) { root.right = node; } else { this.insertNode(root.right, node); } } }
这里所说的树的遍历不仅仅针对二叉搜索树,而是适用于所有的二叉树。由于树结构不是线性结构,所以遍历方式有多种选择,常见的三种二叉树遍历方式为:
还有层序遍历,使用较少。
以遍历根(父)节点的顺序来区分三种遍历方式。比如:先序遍历先遍历根节点、中序遍历第二遍历根节点、后续遍历最后遍历根节点。
代码实现:
// 先序遍历(根左右 DLR) preorderTraversal() { const result = []; this.preorderTraversalNode(this.root, result); return result; } preorderTraversalNode(node, result) { if (node === null) return result; result.push(node.key); this.preorderTraversalNode(node.left, result); this.preorderTraversalNode(node.right, result); }
// 中序遍历(左根右 LDR) inorderTraversal() { const result = []; this.inorderTraversalNode(this.root, result); return result; } inorderTraversalNode(node, result) { if (node === null) return result; this.inorderTraversalNode(node.left, result); result.push(node.key); this.inorderTraversalNode(node.right, result); }
// 后序遍历(左右根 LRD) postorderTraversal() { const result = []; this.postorderTraversalNode(this.root, result); return result; } postorderTraversalNode(node, result) { if (node === null) return result; this.postorderTraversalNode(node.left, result); this.postorderTraversalNode(node.right, result); result.push(node.key); }
在二叉搜索树中查找最值非常简单,最小值在二叉搜索树的最左边,最大值在二叉搜索树的最右边。只需要一直向左/右查找就能得到最值
// min() 获取二叉搜索树最小值 min() { if (!this.root) return null; let node = this.root; while (node.left !== null) { node = node.left; } return node.key; } // max() 获取二叉搜索树最大值 max() { if (!this.root) return null; let node = this.root; while (node.right !== null) { node = node.right; } return node.key; }
查找二叉搜索树当中的特定值效率也非常高。只需要从根节点开始将需要查找节点的 key 值与之比较,若 node.key < root 则向左查找,若 node.key > root 就向右查找,直到找到或查找到 null 为止。这里可以使用递归实现,也可以采用循环来实现。
// search(key) 查找二叉搜索树中是否有相同的key,存在返回 true,否则返回 false search(key) { return this.searchNode(this.root, key); } // 通过递归实现 searchNode(node, key) { if (node === null) return false; if (key < node.key) { return this.searchNode(node.left, key); } else if (key > node.key) { return this.searchNode(node.right, key); } else { return true; } } // 通过 while 循环实现 search2(key) { let node = this.root; while (node !== null) { if (key < node.key) { node = node.left; } else if (key > node.key) { node = node.right; } else { return true; } } return false; }
二叉搜索树的缺陷:当插入的数据是有序的数据,就会造成二叉搜索树的深度过大。
二叉搜索树的缺陷:当插入的数据是有序的数据,就会造成二叉搜索树的深度过大。比如原二叉搜索树由 11 7 15 组成,如下图所示:
当插入一组有序数据:6 5 4 3 2 就会变成深度过大的搜索二叉树,会严重影响二叉搜索树的性能。
非平衡树
树的平衡性
为了能以较快的时间 O(log n)来操作一棵树,我们需要保证树总是平衡的:
常见的平衡树
The text was updated successfully, but these errors were encountered:
No branches or pull requests
二叉搜索树
二叉搜索树(BST,Binary Search Tree),也称为二叉排序树和二叉查找树。
二叉搜索树是一棵二叉树,可以为空。
如果不为空,则满足以下性质:
总结:二叉搜索树的特点主要是较小的值总是保存在左节点上,相对较大的值总是保存在右节点上。这种特点使得二叉搜索树的查询效率非常高,这也就是二叉搜索树中“搜索”的来源。
二叉搜索树的封装
二叉搜索树有四个最基本的属性:指向节点的根(root),节点中的键(key)、左指针(right)、右指针(right)。
所以,二叉搜索树中除了定义 root 属性外,还应定义一个节点内部类,里面包含每个节点中的 left、right 和 key 三个属性。
二叉搜索树的常见操作:
insert(key)
向树中插入一个新的键。search(key)
在树中查找一个键,如果节点存在,则返回 true;如果不存在,则返回false
。preOrderTraverse
通过先序遍历方式遍历所有节点。inOrderTraverse
通过中序遍历方式遍历所有节点。postOrderTraverse
通过后序遍历方式遍历所有节点。min
返回树中最小的值/键。max
返回树中最大的值/键。remove(key)
从树中移除某个键。插入数据
实现思路:
insertNode()
用于查找插入点。insert(key) 代码实现
insertNode() 的实现思路:
根据比较传入的两个节点,一直查找新节点适合插入的位置,直到成功插入新节点为止。
当 newNode.key < node.key 向左查找:
情况 1:当 node 无左子节点时,直接插入:
情况 2:当 node 有左子节点时,递归调用 insertNode(),直到遇到无左子节点成功插入 newNode 后,不再符合该情况,也就不再调用 insertNode(),递归停止。
当 newNode.key >= node.key 向右查找,与向左查找类似:
情况 1:当 node 无右子节点时,直接插入:
情况 2:当 node 有右子节点时,依然递归调用 insertNode(),直到遇到传入 insertNode 方法 的 node 无右子节点成功插入 newNode 为止。
insertNode(root, node) 代码实现
遍历数据
这里所说的树的遍历不仅仅针对二叉搜索树,而是适用于所有的二叉树。由于树结构不是线性结构,所以遍历方式有多种选择,常见的三种二叉树遍历方式为:
还有层序遍历,使用较少。
总结
以遍历根(父)节点的顺序来区分三种遍历方式。比如:先序遍历先遍历根节点、中序遍历第二遍历根节点、后续遍历最后遍历根节点。
先序遍历
代码实现:
中序遍历
代码实现:
后序遍历
代码实现:
查找数据
查找最大值或最小值
在二叉搜索树中查找最值非常简单,最小值在二叉搜索树的最左边,最大值在二叉搜索树的最右边。只需要一直向左/右查找就能得到最值
代码实现:
查找特定值
查找二叉搜索树当中的特定值效率也非常高。只需要从根节点开始将需要查找节点的 key 值与之比较,若 node.key < root 则向左查找,若 node.key > root 就向右查找,直到找到或查找到 null 为止。这里可以使用递归实现,也可以采用循环来实现。
代码实现:
平衡树
二叉搜索树的缺陷:当插入的数据是有序的数据,就会造成二叉搜索树的深度过大。
平衡树
二叉搜索树的缺陷:当插入的数据是有序的数据,就会造成二叉搜索树的深度过大。比如原二叉搜索树由 11 7 15 组成,如下图所示:
当插入一组有序数据:6 5 4 3 2 就会变成深度过大的搜索二叉树,会严重影响二叉搜索树的性能。
非平衡树
树的平衡性
为了能以较快的时间 O(log n)来操作一棵树,我们需要保证树总是平衡的:
常见的平衡树
The text was updated successfully, but these errors were encountered: