代码随想录19|二叉树中的插入操作,删除二叉搜索树中的节点,二叉树的最近公共祖先

文章: 代码随想录

二叉树中的插入操作:

思路:

中序遍历,一定是升序无重复的 //所以只需要中序遍历两两比较再插入就可以.这种思路需要调整二叉树结构,尝试用过morris自己做不出来. //那么题目也允许另一种思路,在合适的null节点处插入节点,所以可以利用搜索二叉树的特性往下遍历到null节点,最后在这个null节点添加新节点就行。

代码:

public static TreeNode insertIntoBST(TreeNode root, int val) {
        TreeNode index=root;
        TreeNode indexNode=new TreeNode(val);
        if(root==null){return indexNode;}
        while (index!=null) {
            //利用二叉树特性,比当前节点大就往右找,反之左找
            if (index.val < val) {
                if (index.right == null) {
                    index.right = indexNode;
                    //插入完之后break,不然继续往下传递的话就是index.val = val,没有这个判断逻辑,会陷入死循环。
                    break;
                }else index=index.right;
            }
            if(index.val>val){
                if(index.left==null){
                    index.left=indexNode;
                    break;
                }else index=index.left;
            }
        }
        return root;
    }

二叉搜索树的最近公共祖先:

思路:

当前想法: // 这题为什么不能用morris遍历呢?我觉得是因为中节点是需要接收左右子树的结果做计算才可以的,不像day17/18中最小绝对差,验证二叉树,众数等这些题, // 只需要遍历一遍树,然后更新结构体中的数据.所以这道题是不适合用的 //那这道题和普通的找最近公共祖先有什么区别? //可以利用二叉搜索树的特性,在寻找目标节点p,q的过程中可以减少节点遍历。 //但其实大体思路和昨天找最近公共祖先题目一样。

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root==null) return null;

        //比目标节点大就往左找
        if(root.val< p.val && root.val< q.val) return lowestCommonAncestor(root.left,p,q);
        //比目标节点小就往右找
        if(root.val> p.val && root.val> q.val) return lowestCommonAncestor(root.right,p,q);
        //剩下 root==p ||root==q,或者是q<root.val<p或者是p<root.val<q.这三种情况
        //为什么这三种情况直接返回root呢?
        //首先第一种,这说明另一个节点在这个节点之下,所以直接返回当前节点即可.
        //第二三种,因为搜索树的特性,证明这两个目标节点,一个是在当前节点的左子树,一个是在当前节点的右子树,当前节点是不是就是这两个目标节点的公共祖先?
        //因为他们向上返回的路径一定会在这个节点相遇吧?
        return root;
    }

删除二叉搜索树中的节点:

思路:

//删除的时候有几种情况

//1.叶子节点 左为空右也为空 -->直接删除

//2. 左为空,右不为空 或者 右空,左不为空 都是前一个指针跳过当前节点指向不为空的节点.

//3. 左右都不为空 那么这里我们采用左孩子上位模式,那么原本的右孩子放在哪呢?

//我们可以找被删除节点的前驱节点,因为这个前驱节点是当前节点的左子树下最大的一个节点,我们就可以直接把右孩子放在这个节点的右节点上。

//那右孩子不是比这个节点的左孩子任意节点都要大吗?为什么不能放在任意左子树的右节点上呢?

//答案是会破会搜索树性质,很明显,如果不是前驱节点的任何节点,要么右子树不为空无法插入,要么这个节点是上面某一个节点的左子树.

//因为前驱节点是一路.right找到的,其它不是这条线上的节点肯定至少都会存在一次.left,那不就违法搜索树了吗?.left应该是都比这个节点要小的值, //但是我们要插入的右子树是比这整个左子树的任意值都要大的,所以找前驱节点。

代码:

public TreeNode deleteNode(TreeNode root, int key) {
        TreeNode cur=root;
        TreeNode pre=null;

        //先根据搜索树特性找到这个节点
        while (cur!=null){
            if (cur.val == key) break;
            pre=cur;
            if(cur.val>key){
                cur=cur.left;
            }else {
                cur=cur.right;
            }
        }
        //如果遍历完了都没找到证明没有
        if(cur==null) return root;
        // 如果搜索树只有头结点,或者删除的是根节点
        if (pre == null) {
            return deleteOneNode(cur);
        }
        //找到了
        //判断在找到key时,cur是pre的左孩子还是右孩子
        //是左孩子
        if(pre.left!=null && pre.left.val==key){
            pre.left=deleteOneNode(cur);
        }

        if(pre.right!=null && pre.right.val==key){
            //是右孩子
            pre.right=deleteOneNode(cur);
        }

        return root;

    }

    private TreeNode deleteOneNode(TreeNode cur) {
        //叶子节点,第一种情况
        if(cur.left==null && cur.right==null){
            cur=null;

        }else if(cur.left==null) {cur=cur.right;}
        else if(cur.right==null){ cur=cur.left;}
        else{
            //最后一种情况,左右都不为空
            TreeNode mostRight=cur.left;
            //找到前驱节点(左子树的最右节点)
            while (mostRight.right!=null) mostRight=mostRight.right;
            //将当前节点的右子树接入
            mostRight.right=cur.right;
            //左孩子继位
            cur=cur.left;
        }
        return cur;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值