当前位置:网站首页>二叉搜索树(特性篇)
二叉搜索树(特性篇)
2022-07-07 14:17:00 【Joey Liao】
首先,BST 的特性大家应该都很熟悉了:
- 对于 BST 的每一个节点
node
,左子树节点的值都比node
的值要小,右子树节点的值都比node
的值大。 - 对于 BST 的每一个节点 node,它的左侧子树和右侧子树都是 BST。
二叉搜索树并不算复杂,但我觉得它可以算是数据结构领域的半壁江山,直接基于 BST 的数据结构有 AVL 树,红黑树等等,拥有了自平衡性质,可以提供 logN 级别的增删查改效率;还有 B+ 树,线段树等结构都是基于 BST 的思想来设计的。
从做算法题的角度来看 BST,除了它的定义,还有一个重要的性质:BST 的中序遍历结果是有序的(升序)。
也就是说,如果输入一棵 BST,以下代码可以将 BST 中每个节点的值升序打印出来:
void traverse(TreeNode root) {
if (root == null) return;
traverse(root.left);
// 中序遍历代码位置
print(root.val);
traverse(root.right);
}
寻找第 K 小的元素
力扣第 230 题「 二叉搜索树中第 K 小的元素」
,一个直接的思路就是升序排序,然后找第 k 个元素呗。BST 的中序遍历其实就是升序排序的结果,找第 k 个元素肯定不是什么难事。
int kthSmallest(TreeNode root, int k) {
// 利用 BST 的中序遍历特性
traverse(root, k);
return res;
}
// 记录结果
int res = 0;
// 记录当前元素的排名
int rank = 0;
void traverse(TreeNode root, int k) {
if (root == null) {
return;
}
traverse(root.left, k);
/* 中序遍历代码位置 */
rank++;
if (k == rank) {
// 找到第 k 小的元素
res = root.val;
return;
}
/*****************/
traverse(root.right, k);
}
如果按照我们刚才说的方法,利用「BST 中序遍历就是升序排序结果」这个性质,每次寻找第 k
小的元素都要中序遍历一次,最坏的时间复杂度是 O(N)
,N
是 BST 的节点个数。
要知道 BST 性质是非常牛逼的,像红黑树这种改良的自平衡 BST,增删查改都是 O(logN)
的复杂度,让你算一个第 k
小元素,时间复杂度竟然要 O(N)
,有点低效了。
那么回到这个问题,想找到第 k
小的元素,或者说找到排名为 k
的元素,如果想达到对数级复杂度,关键也在于每个节点得知道他自己排第几。
比如说你让我查找排名为 k
的元素,当前节点知道自己排名第 m
,那么我可以比较 m
和 k
的大小:
如果 m == k,显然就是找到了第 k 个元素,返回当前节点就行了。
如果 k < m,那说明排名第 k 的元素在左子树,所以可以去左子树搜索第 k 个元素。
如果 k > m,那说明排名第 k 的元素在右子树,所以可以去右子树搜索第 k - m - 1 个元素。
这样就可以将时间复杂度降到 O(logN) 了。
那么,如何让每一个节点知道自己的排名呢?
这就是我们之前说的,需要在二叉树节点中维护额外信息。每个节点需要记录,以自己为根的这棵二叉树有多少个节点。
也就是说,我们 TreeNode 中的字段应该如下:
class TreeNode {
int val;
// 以该节点为根的树的节点总数
int size;
TreeNode left;
TreeNode right;
}
有了 size
字段,外加 BST 节点左小右大的性质,对于每个节点 node
就可以通过 node.left
推导出 node
的排名,从而做到我们刚才说到的对数级算法。
当然,size
字段需要在增删元素的时候需要被正确维护,力扣提供的 TreeNode
是没有 size
这个字段的,所以我们这道题就只能利用 BST 中序遍历的特性实现了,但是我们上面说到的优化思路是 BST 的常见操作,还是有必要理解的。
BST 转化累加树
力扣第 538 题和 1038 题都是这道题 把二叉搜索树转换为累加树
其实就是二叉树的中序遍历,用sum
来记录当前累加和
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode() {} * TreeNode(int val) { this.val = val; } * TreeNode(int val, TreeNode left, TreeNode right) { * this.val = val; * this.left = left; * this.right = right; * } * } */
class Solution {
int sum=0;
public TreeNode convertBST(TreeNode root) {
traverse(root);
return root;
}
public void traverse(TreeNode root){
if(root==null){
return ;
}
traverse(root.right);
sum+=root.val;
root.val=sum;
traverse(root.left);
}
}
边栏推荐
猜你喜欢
Power of leetcode-231-2
平衡二叉树(AVL)
Statistical learning method -- perceptron
torch.numel作用
Eye of depth (VI) -- inverse of matrix (attachment: some ideas of logistic model)
Logback日志框架第三方jar包 免费获取
Excessive dependence on subsidies, difficult collection of key customers, and how strong is the potential to reach the dream of "the first share of domestic databases"?
Apache Doris just "graduated": why should we pay attention to this kind of SQL data warehouse?
Prediction - Grey Prediction
Odoo集成Plausible埋码监控平台
随机推荐
iptables只允许指定ip地址访问指定端口
What are compiled languages and interpreted languages?
华东师大团队提出,具有DNA调控电路的卷积神经网络的系统分子实现
Set the route and optimize the URL in thinkphp3.2.3
Multiplication in pytorch: mul (), multiply (), matmul (), mm (), MV (), dot ()
Eye of depth (VI) -- inverse of matrix (attachment: some ideas of logistic model)
How to query the data of a certain day, a certain month, and a certain year in MySQL
PyTorch 中的乘法:mul()、multiply()、matmul()、mm()、mv()、dot()
How to implement backspace in shell
[vulnhub range] thales:1
Eye of depth (VII) -- Elementary Transformation of matrix (attachment: explanation of some mathematical models)
平衡二叉树(AVL)
删除 console 语句引发的惨案
How to determine whether the checkbox in JS is selected
目标跟踪常见训练数据集格式
Mysql database basic operation DQL basic query
Three singleton modes of unity (hungry man, lazy man, monobehavior)
Leetcode-136- number that appears only once (solve with XOR)
laravel post提交数据时显示异常
The inevitable trend of the intelligent development of ankerui power grid is that microcomputer protection devices are used in power systems