【二叉树】二叉搜索树中的插入操作、删除操作


#学习记录#
今天继续来撕二叉搜索树
对应力扣:
1.二叉搜索树中的插入操作: 701.二叉搜索树中的插入操作
2.删除二叉搜索树中的节点: 450.删除二叉搜索树中的节点

1.二叉搜索树中的插入操作

1.1题目描述

题目

1.2 思路

题目中也提到,我们可能有不同的插入方式,实际上怎么简单怎么来的话,我们直接找遍历到最后的叶子节点,找到之后插入就行,一定会有位置!
根据二叉搜索树的特性,我们直接上迭代法,比较好理解。

1.3 代码(python)

class Solution(object):
    def insertIntoBST(self, root, val):
        """
        :type root: TreeNode
        :type val: int
        :rtype: TreeNode
        """
        result = root
        if not root:
            root = TreeNode(val = val)
            return root
        # 在这里我们要提前设置一个pre,方便我们做插入操作,否则之间遍历到空节点
        pre = None
        while root:
            pre = root
            if root.val > val:
                root = root.left
            else :
                root = root.right
        
        if pre.val > val:
            pre.left = TreeNode(val)
        else:
            pre.right = TreeNode(val)

        return result

2.删除二叉搜索树中的节点

2.1题目描述

二叉树删除节点

2.2 思路

这道题看起来还是有点懵的,如果是叶子节点的话好说,直接删除就是了。但是还涉及了不同位置的节点删除,所以稍显复杂。我们将所有情况罗列出来。

  1. 如果根节点为空,直接返回空节点
  2. 如果要删除的节点右节点为空,左节点不为空,当前节点(cur)直接继承(cur.left)即可,如下
		    5
		   / \
		  3   8
		 /     \
		1       7
		
		删除节点3
		
		    5
		   / \
		  1   8
		       \
		        7

  1. 删除的节点左节点为空,右节点不为空,当前节点(cur)直接继承(cur.right)即可,情况类似2
  2. 删除节点为叶子节点:直接删除即可
  3. 左右节点均不为空(这种情况最为复杂)针对这种情况,我们首先设置一个min_node遍历cur的右子树的左节点,找到其右子树的最小值,另外设置一个min_node_parent最为min_node父节点。找到以后,将min_node的值赋给cur即可。我们就完成了对cur的删除操作。此时,有两种情况,一种情况是min_node是min_node_parent的右孩子,这时代表min_node没有左节点,这种情况我们直接令cur.right = min_node.right。另外一种情况是,cur的右节点有左节点。此时我们还要考虑min_node是否有右节点,如果有,我们把右节点赋给min_node_parent的左节点即可。

上图:

情况一:min_node是min_node_parent的右孩子
在这里插入图片描述
最终:
在这里插入图片描述

情况二:min_node是min_node_parent的左节点:
在这里插入图片描述
最终:
在这里插入图片描述

2.3 代码(python)

直接上代码:

class Solution(object):
    def deleteNode(self, root, key):
        """
        :type root: TreeNode
        :type key: int
        :rtype: TreeNode
        """
        if not root:
            return root
        
        pre = None
        cur = root
        while cur:
            if cur.val == key:
                break  # 找到了要删除的节点
            pre = cur
            cur = cur.left if cur.val > key else cur.right

        if not cur:  # 没有找到要删除的节点
            return root
        
        # 如果当前节点是叶子节点
        if not cur.left and not cur.right:
            if cur == root:  # 要删除的是根节点
                return None
            if pre.left == cur:
                pre.left = None
            else:
                pre.right = None

        # 如果当前节点只有一个子节点
        elif not cur.left or not cur.right:
            child = cur.left if cur.left else cur.right
            if cur == root:  # 要删除的是根节点
                return child
            if pre.left == cur:
                pre.left = child
            else:
                pre.right = child

        # 如果当前节点有两个子节点
        else:
            min_node_parent = cur
            min_node = cur.right  # 找到右子树
            while min_node.left:  # 找到右子树中的最小节点
                min_node_parent = min_node
                min_node = min_node.left
            
            cur.val = min_node.val  # 用最小节点的值替换当前节点的值
            # 删除最小节点,这个节点不会有左子节点
            if min_node_parent.right == min_node:
                cur.right = min_node.right
            else:
                min_node_parent.left = min_node.right
            # 有亿点复杂:将cur的右子树的最左边节点(min_node)放在原来的cur的位置上,然后不确定min_node有没有右节点,有就有,没有就是None
            # 无论有或没有我们都可以把min_node得右节点赋给min_node父节点(min_node_parent.right)
            # 如果min_node_parent.left != min_node,就代表了min_node_parent是min_node的右节点,直接将min_node的右节点连接到cur上即可

        return root

值得注意的一点:
在对节点进行覆盖时,可能有同学会写出:cur = cur.right这样形式的赋值,这样是不正确的。因为,cur只是节点的一个副本,对cur进行修改不会对原树进行改变。想要对cur进行修改的话,我们就要使用到pre节点,也就是它的父节点。

if pre.left == cur:
	pre.left = cur.right
else :
	pre.right = cur.right

以上
学习在于总结和坚持,共勉

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值