二叉搜索树回顾
二叉树的递归和迭代不同于二叉树:
代码随想录给的很清晰:
二叉搜索树的中序遍历就是一个有序的数组
二叉搜索树的递归:返回值就是,返回剩下的节点,便于建立新的父子关系(在迭代中,都是需要单独建立一个父节点)
Leecode题目
701.二叉搜索树中的插入操作
解题关键:遇到空节点就插入节点;返回值完成了新加入节点的父子关系
方法一:递归
三要素:
1.递归函数参数以及返回值
返回值的含义:通过递归函数返回值完成了新加入节点的父子关系赋值操作
2.确定终止条件
找到遍历的节点为null的时候,就是要插入节点的位置了,并把插入的节点返回。
3. 确定单层递归的逻辑
搜索树是有方向了,可以根据插入元素的数值,决定递归方向。
判断节点与目标值的大小,决定往那个方向便宜
class Solution {
public TreeNode insertIntoBST(TreeNode node, int val) {
if(node == null) return new TreeNode(val);
if(node.val>val){
node.left = insertIntoBST(node.left,val);
}else if(node.val<val){
node.right = insertIntoBST(node.right,val);
}
return node;
}
}
方法二:迭代
先用一个类似指针找到应该插入的位置,标记父节点;
再建立父子操作
class Solution {
public TreeNode insertIntoBST(TreeNode root, int val) {
if(root == null) return new TreeNode(val);
// 设置一个指针和指针的父亲
TreeNode cur = root;
TreeNode pre = root;
// 遇到空节点就开始插入,while循环找到父节点
while (cur!= null) {
pre = cur;
if (cur.val > val) {
cur = cur.left;
} else if (cur.val < val) {
cur = cur.right;
}
}
// 建立父子关系,开始插入
if (pre.val > val) {
pre.left = new TreeNode(val);
} else {
pre.right = new TreeNode(val);
}
return root;
}
}
450. 删除二叉搜索树中的节点
要删除某节点(称为 D),必须先找到被删除节点的==父节点( Parent)==和托孤
- 删除节点没有左孩子,将右孩子托孤给 Parent
- 删除节点没有右孩子,将左孩子托孤给 Parent
- 删除节点左右孩子都没有,已经被涵盖在情况1、情况2 当中,把 null 托孤给 Parent
- 删除节点左右孩子都有,可以将它的后继节点(称为 S)托孤给 Parent,设 S 的父亲为 SP,又分两种情况
- SP 就是被删除节点,此时 D 与 S 紧邻,只需将 S 托孤给 Parent
- SP 不是被删除节点,此时 D 与 S 不相邻,此时需要将 S 的后代托孤给 SP,再将 S 托孤给 Parent
方法一:迭代
解析:按照满老师的视频,在托孤的方法那里, p a r e n t = = n u l l parent==null parent==null的情况,自己又单独写了删除节点的情况
class Solution {
public TreeNode deleteNode(TreeNode node, int val) {
// 1.先找删除节点的父亲
TreeNode cur = node;
TreeNode parent = null;
while(cur!=null){
if(cur.val>val){
parent = cur;
cur = cur.left;
}else if(cur.val<val){
parent = cur;
cur = cur.right;
}else{
break;
}
}
// 1.如果没找到目标,直接返回
if(cur == null){
return node;
}
// 删除根节点,就不能用shift方法
if(parent == null){
TreeNode s =null;
//只有一个节点
if(node.left == null){
return node.right;
}else if(node.right == null){
return node.left;
}else{ // 两边都有
// 找到比它大的兄弟
s = cur.right; // 长兄
TreeNode sparent = cur; // 长兄他爸
while(s.left!=null){
sparent = s;
s = s.left;
}
//把长兄的孩子托福给长兄的父亲
//(1) 长兄的父亲不是被删除节点,长兄只有右孩子
if(sparent !=cur){
shift(sparent,s,s.right);
s.right = cur.right;
s.left = cur.left;
}else{
s.left = cur.left;
}
}
return s;
}
else{
//2.开始删除节点
deleted(cur,parent);
return node;
}
}
public void deleted(TreeNode cur, TreeNode parent){
//2.开始删除节点
//2.1 最多只有一个节点
if(cur.left ==null){
shift(parent,cur,cur.right);
}else if(cur.right == null){
shift(parent,cur,cur.left);
}else {
//2.2 被删除有俩孩子,长兄为父(长兄是被删除节点的右子树的最后一个左节点)
TreeNode s = cur.right; // 长兄
TreeNode sparent = cur; // 长兄他爸
while(s.left!=null){
sparent = s;
s = s.left;
}
//把长兄的孩子托福给长兄的父亲
//(1) 长兄的父亲不是被删除节点,长兄只有右孩子
if(sparent != cur){
shift(sparent,s,s.right);
s.right = cur.right;
s.left = cur.left;
shift(parent,cur,s);
}else{
s.left = cur.left;
shift(parent,cur,s);
}
}
}
// 托孤方法:只改变父节点的指向,没改变被删除节点的指向
public void shift(TreeNode parent,TreeNode deleted,TreeNode child){
if(deleted == parent.left) parent.left = child;
else if(deleted == parent.right) parent.right = child;
}
}
方法二:递归
三要素:返回值和形参,返回删剩下的节点(建立新的节点和之前的父节点之间的父子关系)
终止条件,遍历到空节点直接返回
单层递归逻辑:上述的五种情况
满老师讲的很好
class Solution {
public TreeNode deleteNode(TreeNode node, int val) {
// 1.停止条件
if(node == null) return null;
//2.没找到
if(node.val<val){
node.right = deleteNode(node.right,val);
return node;
}
if(node.val>val){
node.left = deleteNode(node.left,val);
return node;
}
//(node.val == val)找到了(那五种情况)
if(node.left == null){ //只有右孩子
return node.right;
}
if(node.right == null){//只有左孩子
return node.left;
}
// 俩孩子
TreeNode s = node.right;
while(s.left!=null){
s= s.left;
}
//不相邻(从删除节点的右子树出发,先处理长兄)
s.right = deleteNode(node.right,s.val);
// 长兄和被删除节点相邻
s.left = node.left;
return s;
}
}