Day21|算法记录

二叉搜索树回顾

二叉树的递归和迭代不同于二叉树
代码随想录给的很清晰:
二叉搜索树的中序遍历就是一个有序的数组

二叉搜索树的递归:返回值就是,返回剩下的节点,便于建立新的父子关系(在迭代中,都是需要单独建立一个父节点)

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)==和托孤

  1. 删除节点没有左孩子,将右孩子托孤给 Parent
  2. 删除节点没有右孩子,将左孩子托孤给 Parent
  3. 删除节点左右孩子都没有,已经被涵盖在情况1、情况2 当中,把 null 托孤给 Parent
  4. 删除节点左右孩子都有,可以将它的后继节点(称为 S)托孤给 Parent,设 S 的父亲为 SP,又分两种情况
    1. SP 就是被删除节点,此时 D 与 S 紧邻,只需将 S 托孤给 Parent
    2. 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;
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值