二叉树的构建与增删改查(2) 删除节点

前置知识:二叉树的构建和增删改查-CSDN博客

1.二叉树的删除特点

1.1 基本概念

二叉树的删除操作是指在二叉树中移除某个特定节点,同时需要保持二叉树的基本性质不变。删除操作比插入操作更为复杂,因为需要考虑被删除节点的子树如何重新连接到树上。

1.2 删除操作的三种主要情况

1.2.1 删除叶子节点(无子节点)

  • 这是最简单的情况,直接移除该节点即可

  • 示例:在二叉树中删除节点5(假设5是叶子节点)

    复制代码
       5
      / \
     3   7

    删除后:

    复制代码
       3
        \
         7

1.2.2 删除只有一个子节点的节点

  • 将该节点的子节点提升到被删除节点的位置

  • 示例:删除节点3(它只有右子节点7)

    复制代码
       5
      / \
     3   8
      \
       7

    删除后:

    复制代码
       5
      / \
     7   8

1.2.3 删除有两个子节点的节点

这是最复杂的情况,通常有以下两种处理方法:

方法一:使用前驱节点(左子树的最大值)
  1. 找到被删除节点左子树中的最大值节点
  2. 用这个最大值节点替换被删除节点
  3. 删除原最大值节点(递归处理)
方法二:使用后继节点(右子树的最小值)
  1. 找到被删除节点右子树中的最小值节点
  2. 用这个最小值节点替换被删除节点
  3. 删除原最小值节点(递归处理)

示例:删除节点5

复制代码
     5
    / \
   3   8
  / \ / \
 2  4 7 9

使用后继节点方法:

  1. 找到右子树最小值7
  2. 用7替换5
  3. 删除原7节点

结果:

复制代码
     7
    / \
   3   8
  / \ / \
 2  4 9

2.操作流程

图示操作可见1.2

2.1 除叶子节点

  1. 定位需要删除的目标节点targetNode
  2. 查找targetNode的父节点parentNode,并判断其是否存在
  3. 确定targetNode是parentNode的左子树还是右子树
  4. 根据节点位置执行删除操作:
    • 若为左子节点:将parentNode.lChild置为null
    • 若为右子节点:将parentNode.rChild置为null

2.2 删除只有一个子树的节点

  1. 定位需要删除的目标节点targetNode
  2. 查找targetNode的父节点parentNode(需判断是否存在)
  3. 确定targetNode在parentNode中的位置(左子树或右子树)
  4. 根据targetNode的子节点情况进行处理:

情况一:targetNode是parentNode的左子树

  • 若targetNode存在左子节点:parentNode.lChild = targetNode.lChild
  • 若targetNode存在右子节点:parentNode.lChild = targetNode.rChild

情况二:targetNode是parentNode的右子树

  • 若targetNode存在左子节点:parentNode.rChild = targetNode.lChild
  • 若targetNode存在右子节点:parentNode.rChild = targetNode.rChild

2.3 删除有两子树的节点

  1. 定位目标删除节点targetNode
  2. 查找targetNode的父节点parentNode(需判断是否存在)
  3. 在targetNode的右子树中寻找最小值节点
  4. 用右子树最小值节点的值替换targetNode的值
  5. 删除右子树中的最小值节点

3. 前置操作

3.1 创建方法用于寻找targetNode

java 复制代码
public TreeNode findTarget(TreeNode root, Integer target) {
        if (root == null || target == null) return null;
        TreeNode cur = root;
        while (cur != null) {
            if (cur.data.equals(target)) {
                return cur;
            } else if (cur.data < target) {
                cur = cur.rChild;
            } else {
                cur = cur.lChild;
            }
        }
        return null;
    }

3.2 创建方法用于去找要删除的节点的父节点

java 复制代码
public TreeNode findParent(TreeNode root,Integer target){
        if(root==null){
            return null;
        }
        if((root.lChild!=null) && (root.lChild.data.equals(target))|| (root.rChild!=null) && (root.rChild.data.equals(target))){
            return root;
        }else {
            if(root.lChild!=null && target<root.data){
                return findParent(root.lChild,target);
            }else if(root.rChild!=null && target>root.data){
                return findParent(root.rChild,target);
            }else {
                return null;
            }
        }
    }

3.3 寻找右子树的最小节点

java 复制代码
public int findRightTreeMin(TreeNode node){

        while (node.lChild!=null){
            node = node.lChild;
        }
        int min = node.data;
        delete(root,min);
        return min;
    }

4.删除节点

4.1 删除的节点只有一个节点

java 复制代码
if(root.lChild==null && root.rChild==null){//删除的是叶子节点
            root=null;
            return;
        }

4.2 叶子节点

java 复制代码
 if (targetNode.lChild == null && targetNode.rChild == null) { // 叶子节点
            // 确定targetNdoe 是parentNode的左子节点还是右子节点
            if (parentNode.lChild != null && parentNode.lChild.data.equals(target)) {
                parentNode.lChild = null;
            }else if (parentNode.rChild != null && parentNode.rChild.data.equals(target)) {
                parentNode.rChild = null;
            }
        

4.3 两个子节点

java 复制代码
if (targetNode.lChild != null && targetNode.rChild != null) { // 两个子节点的节点
            int min = findRightTreeMin(targetNode.rChild);//寻找右子树最小的节点
            targetNode.data = min;
        } 

4.4 只有一个子节点的节点

java 复制代码
if(parentNode.lChild!=null && parentNode.lChild.data.equals(target)){
                // targetNode是parentNode的左子节点
                if(targetNode.lChild!=null){//删除的是有子节点的节点
                    parentNode.lChild = targetNode.lChild;
                }else if(targetNode.rChild!=null){//删除的是有子节点的节点
                    parentNode.lChild = targetNode.rChild;
                }
            }else if(parentNode.rChild!=null && parentNode.rChild.data.equals(target)){
                // targetNode是parentNode的右子节点
                if(targetNode.lChild!=null){//删除的是有子节点的节点
                    parentNode.rChild = targetNode.lChild;
                }else if(targetNode.rChild!=null){//删除的是有子节点的节点
                    parentNode.rChild = targetNode.rChild;
                }
            }

完整代码:

java 复制代码
//删除节点
    public void delete(TreeNode root,Integer target){
        if (root==null){
            return;
        }
        //2.万一要删除的节点只有一个节点
        if(root.lChild==null && root.rChild==null){//删除的是叶子节点
            root=null;
            return;
        }
        //1.找要删除的节点
        TreeNode targetNode = findTarget(root,target);
        if(targetNode==null){
            return;
        }
        //3.找到父节点
        TreeNode parentNode = findParent(root,target);

        // 请你进行讲解
        if (targetNode.lChild == null && targetNode.rChild == null) { // 叶子节点
            // 确定targetNdoe 是parentNode的左子节点还是右子节点
            if (parentNode.lChild != null && parentNode.lChild.data.equals(target)) {
                parentNode.lChild = null;
            }else if (parentNode.rChild != null && parentNode.rChild.data.equals(target)) {
                parentNode.rChild = null;
            }
        } else if (targetNode.lChild != null && targetNode.rChild != null) { // 两个子节点的节点
            int min = findRightTreeMin(targetNode.rChild);//寻找右子树最小的节点
            targetNode.data = min;
        } else { // 只有一个子节点的节点
            // 确定targetNdoe 是parentNode的左子节点还是右子节点
            if(parentNode.lChild!=null && parentNode.lChild.data.equals(target)){
                // targetNode是parentNode的左子节点
                if(targetNode.lChild!=null){//删除的是有子节点的节点
                    parentNode.lChild = targetNode.lChild;
                }else if(targetNode.rChild!=null){//删除的是有子节点的节点
                    parentNode.lChild = targetNode.rChild;
                }
            }else if(parentNode.rChild!=null && parentNode.rChild.data.equals(target)){
                // targetNode是parentNode的右子节点
                if(targetNode.lChild!=null){//删除的是有子节点的节点
                    parentNode.rChild = targetNode.lChild;
                }else if(targetNode.rChild!=null){//删除的是有子节点的节点
                    parentNode.rChild = targetNode.rChild;
                }
            }
        }

总结:

删除二叉树中的节点需要根据节点类型(叶子节点、单子节点、双子节点)采取不同策略,同时保持二叉树的特性(如二叉搜索树的顺序性)。

删除叶子节点

直接移除该节点,并将其父节点的对应子节点指针置空。无需调整树结构。

删除单子节点

将该节点的唯一子节点提升到被删除节点的位置,保持树的连通性。

删除双子节点

对于有两个子节点的节点,通常采用以下两种方法之一:

方法1:前驱替换法 找到左子树的最大节点(前驱),用其值替换待删除节点,然后递归删除前驱节点。

方法2:后继替换法 找到右子树的最小节点(后继),用其值替换待删除节点,然后递归删除后继节点。

完整删除流程(二叉搜索树示例)
  1. 定位待删除节点及其父节点
  2. 根据节点类型选择删除策略
  3. 维护树结构完整性
  4. 返回更新后的树根节点
相关推荐
黎雁·泠崖19 小时前
二叉树实战进阶全攻略:从层序遍历到OJ题深度解析
c语言·数据结构·leetcode
散峰而望19 小时前
【算法竞赛】顺序表和vector
c语言·开发语言·数据结构·c++·人工智能·算法·github
cpp_250119 小时前
B3927 [GESP202312 四级] 小杨的字典
数据结构·c++·算法·题解·洛谷
Cx330❀19 小时前
《C++ 递归、搜索与回溯》第2-3题:合并两个有序链表,反转链表
开发语言·数据结构·c++·算法·链表·面试
独自破碎E19 小时前
链表相加(二)
数据结构·链表
CCPC不拿奖不改名19 小时前
面向对象编程:继承与多态+面试习题
开发语言·数据结构·python·学习·面试·职场和发展
꧁Q༒ོγ꧂19 小时前
算法详解(二)--算法思想基础
java·数据结构·算法
黎雁·泠崖19 小时前
二叉树综合拔高:遍历还原与OJ题拓展训练
c语言·数据结构·leetcode
漫随流水21 小时前
leetcode算法(111.二叉树的最小深度)
数据结构·算法·leetcode·二叉树
kaikaile19951 天前
基于拥挤距离的多目标粒子群优化算法(MO-PSO-CD)详解
数据结构·算法