二叉树的插入、查找、删除

树结点的定义:
public class Tree {
    public int data;
    //左孩子
    public Tree lchild;
    //右孩子
    public Tree rchild;
}

通过下面的方法对这个二叉树进行插入、查询、删除操作。

插入:

    通过循环的方式对二叉树进行结点插入。插入也相当于创建一个二叉查找树。
代码示例:

public void insert(int value) {
        //当前节点
        Tree current;
        //父节点
        Tree parent;
        //创建新节点
        Tree node = new Tree(value);

        //如果根节点为空,将新创建的节点当作根节点
        if (root == null) {
            root = node;
            return;
        } else {
            //把当前节点当作根节点
            current = root;
            while (current != null) {
                //遍历左子树
                if (value < current.data) {
                    parent = current;
                    current = parent.lchild;
                    //遍历到叶子节点,插入新结点
                    if (current == null) {
                        parent.lchild = node;
                        return;
                    }
                } else { //遍历右子树
                    parent = current;
                    current = parent.rchild;
                    //遍历到叶子节点,插入新结点
                    if (current == null) {
                        parent.rchild = node;
                        return;
                    }
                }
            }
        }
    }
	//方法重载
    public void insertValues(int[] value) {
        for (int i = 0; i < value.length; i++) {
            insert(value[i]);
        }
    }
总结

1.给定一个数组,根据这个数组在二叉树中进行值的插入。

查找:

    因为这是一棵二叉搜索树,所以查找类似于二分查找法
代码示例:

public boolean search(int value) {
        Tree parent;
        Tree current;

        if (root == null) {
            return false;
        } else {
            current = root;

            while (current != null) {
                if (value == current.data) { //找到结点返回true
                    return true;
                } else if (value < current.data) {
                    parent = current;
                    current = parent.lchild;

                    if (current == null) {
                        return false;
                    }
                } else {
                    parent = current;
                    current = parent.rchild;

                    if (current == null) {
                        return false;
                    }
                }
            }
        }
        return false;
    }
总结
  1. 给定一个值,判断这个值在不在这个二叉树中。
删除:

    这里重点说一下删除。二叉树的删除操作比较复杂,因为一个结点可能没有孩子结点,也可能有一个孩子结点,也可能有两个孩子结点,所以删除二叉树的结点需要分情况讨论:
1. 删除结点没有孩子结点是叶子结点;
2. 删除结点只有一个孩子结点;
    2.1 删除结点没有右孩子结点;
    2.2.删除结点没有左孩子结点;
3. 删除结点左右孩子结点都存在;
有两种办法:a.让删除结点的左子树最大值(也可以理解为中序遍历的直接前继)接替删除的位置;b.让删除结点的右子树最小值(也可以理解为中序遍历的直接后继)接替删除的位置;)。这里采用的是b方法

注意:每种种情况都需要判断是不是根结点;
接下来看一下具体的删除过程:

1.查找到要删除的结点,并且判断是左结点还是右结点;

代码示例:

//遍历查找删除结点
while (current.data != value) {
    parent = current;
    //走左子树
    if (value < current.data) {
        current = current.lchild;
        isLeftChild = true;
    } else {  //走右子树
        current = current.rchild;
        isLeftChild = false;
    }
    //说明没有找到删除结点
    if (current == null) {
        return false;
    }
}
2.删除结点没有孩子结点是叶子结点;

如下图:
在这里插入图片描述
如果删除是左叶子结点,直接让父结点的左孩子为null;否则有孩子为null;
代码示例:

//1. 删除的是叶子结点
if (current.rchild == null && current.lchild == null) {
    //若删除的结点为根结点
    if (current == root) {
        root = null;
    } else { //删除结点为非根节点的叶子结点
        if (isLeftChild) {
            parent.lchild = null;
        } else {
            parent.rchild = null;
        }
    }
}
3.删除结点只有一个孩子结点;
3.1 删除结点没有右孩子结点;

可能会有两种情况:
1. 删除结点是左孩子,并且没有右子树;
在这里插入图片描述
2.删除结点是右孩子,并且没有右子树;
在这里插入图片描述
**结果:**都是让父结点直接指向删除结点的子结点;
代码示例:

//2.1 若删除的结点没有右子树
if (current.rchild == null) { 
    if (current == root) {
        root = current.lchild;
    } else {
        if (isLeftChild) {
            parent.lchild = current.lchild;
        } else {
            parent.rchild = current.lchild;
        }
    }
}
3.2 删除结点没有左孩子结点;

可能会存在两种情况:
1.删除结点是左孩子,并且没有左子树;
在这里插入图片描述
2.删除结点是右孩子,并且没有左子树;
在这里插入图片描述
**结果:**都是让父结点直接指向删除结点的子结点;
代码示例:

//2.2 若删除的结点没有左子树
if (current.lchild == null) { 
    if (current == root) {
        root = current.rchild;
    } else {
        if (isLeftChild) {
            parent.lchild = current.rchild;
        } else {
            parent.rchild = current.rchild;
        }
    }
}
4 删除结点左右孩子结点都存在;

如下图:
在这里插入图片描述
假设要删除的结点是4,需要找到右子树的最小值(中序遍历后的直接后继结点)接替4结点的位置。
代码示例:

//找到删除结点中序遍历后的直接后继结点并返回
private Tree succeed(Tree delete) {
    //父节点
    Tree parent = delete;
    //表示删除结点的后继结点
    Tree succeed = delete;
    //当前遍历的结点
    Tree current = delete.rchild;
    //遍历到删除结点中序遍历的直接后继结点
    while (current != null) {
        parent = succeed;
        succeed = current;
        current = current.lchild;
    }
    //说明删除的结点的右结点存在左子树
    if (succeed != delete.rchild) {
        //让后继结点的父节点指向后继结点的右子树
        parent.lchild = succeed.rchild;
        //将后继结点指向删除结点的右子树,完成替换
        succeed.rchild = delete.rchild;
    }

    return succeed;
}

执行完该方法,删除结点的右子树结构会变成这样:
在这里插入图片描述
然后把5结点返回;
执行下面的代码:
代码示例:

//3. 若删除的结点左右子树都存在
if{  
    //找到删除结点中序遍历后的直接后继结点并返回
    Tree succeed = succeed(current);
    if (current == root) {
        root = succeed;
    } else {
        if (isLeftChild) {
            parent.lchild = succeed;
        } else {
            parent.rchild = succeed;
        }
    }
    //让后继结点连接到删除结点的左子树
    succeed.lchild = current.lchild;
}

首先对删除结点判断,
1.如果是根结点:
则后继结点直接设为根结点,并且让删除结点的左子树连接到该后继结点上;
在这里插入图片描述

①找到删除结点4的后继结点5;
②调整树结构并返回;
③让删除结点的左子树直接当作后继结点的左子树;

2.不是根结点,如果删除结点是左孩子,让父结点的左孩子直接为后继结点,否则让右孩子直接为后继结点,最后让删除结点的左子树连接到该后继结点上。
在这里插入图片描述
③让父结点指向该后继结点,让删除结点的左子树直接当作后继结点的左子树;
下面看一下是删除二叉树结点的具体的代码,里面有详细的注释:
代码示例:

public boolean delete(int value) {
    //父结点
    Tree parent = root;
    //当前结点
    Tree current = root;
    //判断被删结点是否是左结点
    boolean isLeftChild = true;
    //若是根结点直接返回
    if (root == null) {
        return false;
    }
    //遍历查找删除结点
    while (current.data != value) {
        parent = current;
        //走左子树
        if (value < current.data) {
            current = current.lchild;
            isLeftChild = true;
        } else {  //走右子树
            current = current.rchild;
            isLeftChild = false;
        }
        //说明没有找到删除结点
        if (current == null) {
            return false;
        }
    }
    //1. 删除的是叶子结点
    if (current.rchild == null && current.lchild == null) {
        //若删除的结点为根结点
        if (current == root) {
            root = null;
        } else { //删除结点为非根节点的叶子结点
            if (isLeftChild) {
                parent.lchild = null;
            } else {
                parent.rchild = null;
            }
        }
    } else if (current.rchild == null) { //2.1 若删除的结点没有右子树
        if (current == root) {
            root = current.lchild;
        } else {
            if (isLeftChild) {
                parent.lchild = current.lchild;
            } else {
                parent.rchild = current.lchild;
            }
        }
    } else if (current.lchild == null) { //2.2 若删除的结点没有左子树
        if (current == root) {
            root = current.rchild;
        } else {
            if (isLeftChild) {
                parent.lchild = current.rchild;
            } else {
                parent.rchild = current.rchild;
            }
        }
    } else {  //3. 若删除的结点左右子树都存在
        //找到删除结点中序遍历后的直接后继结点并返回
        Tree succeed = succeed(current);
        if (current == root) {
            root = succeed;
        } else {
            if (isLeftChild) {
                parent.lchild = succeed;
            } else {
                parent.rchild = succeed;
            }
        }
        //让后继结点连接到删除结点的左子树
        succeed.lchild = current.lchild;
    }
    return true;
}
//找到删除结点中序遍历后的直接后继结点并返回
private Tree succeed(Tree delete) {
    //父节点
    Tree parent = delete;
    //表示删除结点的后继结点
    Tree succeed = delete;
    //当前遍历的结点
    Tree current = delete.rchild;
    //遍历到删除结点中序遍历的直接后继结点
    while (current != null) {
        parent = succeed;
        succeed = current;
        current = current.lchild;
    }
    //说明删除的结点的右结点存在左子树
    if (succeed != delete.rchild) {
        //让后继结点的父节点指向后继结点的右子树
        parent.lchild = succeed.rchild;
        //将后继结点指向删除结点的右子树,完成替换
        succeed.rchild = delete.rchild;
    }

    return succeed;
}

注意:里面的root为该类的一个属性。

  • 5
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是 Python 实现的二叉树插入查找删除节点的代码示例: ```python class Node: def __init__(self, val): self.val = val self.left = None self.right = None class BinaryTree: def __init__(self): self.root = None # 插入节点 def insert(self, val): if not self.root: self.root = Node(val) else: self._insert(val, self.root) def _insert(self, val, node): if val < node.val: if node.left: self._insert(val, node.left) else: node.left = Node(val) else: if node.right: self._insert(val, node.right) else: node.right = Node(val) # 查找节点 def search(self, val): if not self.root: return False else: return self._search(val, self.root) def _search(self, val, node): if not node: return False elif node.val == val: return True elif val < node.val: return self._search(val, node.left) else: return self._search(val, node.right) # 删除节点 def delete(self, val): if not self.root: return False else: self.root = self._delete(val, self.root) def _delete(self, val, node): if not node: return node elif val < node.val: node.left = self._delete(val, node.left) elif val > node.val: node.right = self._delete(val, node.right) else: if not node.left: return node.right elif not node.right: return node.left else: temp = self._find_min(node.right) node.val = temp.val node.right = self._delete(temp.val, node.right) return node def _find_min(self, node): while node.left: node = node.left return node ``` 以上是二叉树的基本操作,具体使用方式可以参考以下示例: ```python bt = BinaryTree() # 插入节点 bt.insert(5) bt.insert(3) bt.insert(7) bt.insert(1) bt.insert(9) # 查找节点 print(bt.search(7)) # True print(bt.search(4)) # False # 删除节点 bt.delete(3) print(bt.search(3)) # False ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值