1 概念
二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树
:
- 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
- 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
- 它的左右子树也分别为二叉搜索树
2.查找
图解:
TreeNode searchBST(TreeNode root, int val){
if(root==null){
return null;
}
if(root.val==val){
return root;
}
while(cur!=null){
if(cur.val>val){
cur=cur.right;
}
else if(cur.val<val){
cur=cur.left;
}
}
return root;
}
如果采用递归操作:
TreeNode searchBST(TreeNode root, int val) {
if (root == null) {
return null;
}
// 去左子树搜索
if (root.val > val) {
return searchBST(root.left, target);
}
// 去右子树搜索
if (root.val < val) {
return searchBST(root.right, target);
}
return root;//上面两个都不满足,说明root.val == val直接返回root
}
3. 操作-插入
具体步骤:
-
insertIntoBST 方法:
检查树是否为空,如果为空则创建根节点。
- 使用
while
循环遍历树,找到合适的插入位置。 - 如果当前节点的值大于
key
,则向左子树移动;如果小于,则向右子树移动。 - 如果发现节点的值与要插入的值相同,则返回根节点,表示不插入相同节点。
- 将新节点连接到找到的父节点的左或右子树。
采用双指针:
public TreeNode insertIntoBST(int key) {
// 如果树为空,创建根节点
if (root == null) {
root = new TreeNode(key);
return root;
}
TreeNode cur = root;
TreeNode parent = null;
TreeNode node = new TreeNode(key);
// 查找插入位置
while (cur != null) {
parent = cur; // 记录当前节点的父节点
if (cur.val > key) {
cur = cur.left; // 向左子树移动
} else if (cur.val < key) {
cur = cur.right; // 向右子树移动
} else {
return root; // 不允许插入相同的节点
}
}
// 将新节点连接到父节点
if (parent.val > key) {
parent.left = node; // 插入到左子树
} else {
parent.right = node; // 插入到右子树
}
return root; // 返回根节点
}
采用递归方法:
TreeNode insertIntoBST(TreeNode root, int val) {
// 找到空位置插入新节点
if (root == null)
return new TreeNode(val);
//这里就相当于将节点接入到二叉树对应的叶子中
if (root.val == val) {return root;}
//BST 中一般不会插入已存在元素
if (root.val < val)
root.right = insertIntoBST(root.right, val);
if (root.val > val)
root.left = insertIntoBST(root.left, val);
return root;
}
4.删除:
-
deleteNode 方法:
- 实现删除节点的逻辑。
- 如果找到了需要删除的节点,判断其子节点情况:
-
情况 1:节点没有子节点,直接返回
null
。 - 情况 2:节点只有一个子节点,返回那个子节点。
- 情况 3:节点有两个子节点,找到右子树的最小节点,替换当前节点,并删除右子树的最小节点。
-
情况 1:节点没有子节点,直接返回
TreeNode deleteNode(TreeNode root,int val{
if(root==null){return null;}
if(root.val>key){
root.left=deleteNode(root.left,val);
}else if(root.val<key){
root.left=deleteNode(root.right,val);
}
return root;
}
情况 1:A 恰好是末端节点,且左右子节点都为空,则释放当前节点。
if (root.left == null && root.right == null)
return null;
情况 2:A 只有一个非空子节点,那么与他的孩子节点互换位置,后是放尾节点。
if (root.left == null) return root.right;
if (root.right == null) return root.left;
情况 3:A 有两个子节点,麻烦了,为了不破坏 BST 的性质,A 必须找到左子树中最大的那个节点,或者右子树中最小的那个节点互换。
if (root.left!= null && root.right != null) {
// 找到右子树的最小节点
TreeNode minNode = getMin(root.right);
// 把 root 改成 minNode
root.val = minNode.val;
// 转而去删除 minNode
root.right = deleteNode(root.right, minNode.val);
}
三中情况都完成后,整理一下代码:
// 删除节点方法
public TreeNode deleteNode(TreeNode root, int key) {
if (root == null) return null; // 空树情况
if (root.val == key) {
// 情况 1 和 2: 只有一个子节点或没有子节点
if (root.left == null) return root.right;
if (root.right == null) return root.left;
// 情况 3: 两个子节点
// 获取右子树的最小节点
TreeNode minNode = getMin(root.right);
// 删除右子树的最小节点
root.right = deleteNode(root.right, minNode.val);
// 用右子树最小的节点替换 root 节点
minNode.left = root.left;
minNode.right = root.right;
root = minNode;
} else if (root.val > key) {
root.left = deleteNode(root.left, key); // 在左子树中删除
} else {
root.right = deleteNode(root.right, key); // 在右子树中删除
}
return root; // 返回更新后的根节点
}
// 获取最小节点
public TreeNode getMin(TreeNode node) {
// BST 最左边的节点就是最小的节点
while (node.left != null) node = node.left;
return node;
}
到这里竹竹零就要和大家说再见了
希望时光不负赶路人,愿我们做最好的自己!!!
如果您觉得有失偏颇请您在评论区指正,如果您觉得不错的话留个好评再走吧!!
您的鼓励就是对我最大的支持! ! !