数据结构与算法--二叉排序树/二叉查找树/二叉搜索树 Python实现二叉排序树/二叉查找树/二叉搜索树的遍历、查找、删除 Python最简单的方式实现二叉排序树

基本概述

  • 如何更加高效的完成对数据的查询和添加操作,例如↓↓↓
    在这里插入图片描述
  • 之前解决方案的优缺点
    在这里插入图片描述
  • 树结构解决方案:二叉排序树
    在这里插入图片描述

二叉排序树的创建和遍历

class TreeNode(object):
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None
        
class BinarySortTree(object):
    def __init__(self):
        self.root = None

    # 添加结点
    def add(self, val):  
        node = TreeNode(val)
        if self.root is None:
            self.root = node
            return
        queue = [self.root]
        while queue:
            temp_node = queue.pop(0)
            # 判断传入结点的值和当前子树结点的值关系
            if node.val < temp_node.val:
                if temp_node.left is None:
                    temp_node.left = node
                    return
                else:
                    queue.append(temp_node.left)
            if node.val >= temp_node.val:
                if temp_node.right is None:
                    temp_node.right = node
                    return
                else:
                    queue.append(temp_node.right)

    # 中序遍历
    def in_order(self, node):
        if node is None:
            return
        self.in_order(node.left)
        print(node.val, end=" ")
        self.in_order(node.right)


if __name__ == '__main__':
    t = BinarySortTree()
    note_array = [7, 3, 10, 12, 5, 1, 9]
    for item in note_array:
        t.add(item)
    t.in_order(t.root)
'''输出结果
1,3,5,7,9,10,12
刚好是升序
'''

二叉排序树的删除

删除时会遇到的情况
  • 要处理的各种情况
    在这里插入图片描述

  • 第一种情况:删除叶子结点
    在这里插入图片描述

  • 第二种情况:删除只有一棵子树的结点
    在这里插入图片描述

  • 第三种情况:删除有两课子树的结点
    在这里插入图片描述
    (1)上图为,target_node的右子树只有一个结点,那它就是最小的
    在这里插入图片描述
    (2)下图,假设当target_node的右子树,还有一个11,那么11就是最小的,需要把11的值放到target_node的位置
    在这里插入图片描述

先实现查找要删除的结点
'''上面代码一样,先省略'''
    def search(self, node, val):
        '''
        :param node: 传入根结点
        :param val: 传入要查找的值
        :return: 找到返回该node,没找到返回None
        '''    
        if node is None:
            return None
        if node.val == val:
            return node
        if val < node.val:
            return self.search(node.left, val)
        else:
            return self.search(node.right, val)
            
if __name__ == '__main__':
    t = BinarySortTree()
    note_array = [7, 3, 10, 12, 5, 1, 9]
    for item in note_array:
        t.add(item)
    search_node =t.search(t.root, 3) # 3
    if search_node: # 只为测试用
    	print(search_node.val)
    else:
    	print(search_node)
查找要删除节点的父结点
'''上面代码一样,先省略'''
    # 查找结点的父结点
    def parent(self, node, val):
        '''
        :param node: 传入根结点
        :param val: 传入要找的父结点的值
        :return: 如果找到返回该父结点,如果没有返回None
        '''
        if node is None:  # 如果要找的值遍历完二叉树还不存在,由此退出并返回None
            return None
        if self.root.val == val:  # 根结点没有父结点
            return None
        # 如果当前结点的左子结点或者右子结点存在,并且值就是要找的,直接返回它的父结点
        if (node.left and node.left.val == val) or (node.right and node.right.val == val):
            return node
        else:
            # 如果要找的结点值小于父结点且它的左子结点存在,向左递归
            if val < node.val and node.left:
                return self.parent(node.left, val)
            # 如果要找的结点值大于父结点且它的右子结点存在,向左递归
            elif node.val < val and node.right:
                return self.parent(node.right, val)


if __name__ == '__main__':
    t = BinarySortTree()
    note_array = [7, 3, 10, 12, 5, 1, 9]
    for item in note_array:
        t.add(item)
    # t.in_order(t.root)
    # print(t.search(t.root, 3))
    parent_node = t.parent(t.root, 1)  # 3
    if parent_node: # 只为输出测试
        print(parent_node.val)
    else:
        print(parent_node)
完整实现二叉排序树的删除结点操作
class TreeNode(object):
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None


class BinarySortTree(object):
    def __init__(self):
        self.root = None

    # 添加结点
    def add(self, val):  
        node = TreeNode(val)
        if self.root is None:
            self.root = node
            return
        queue = [self.root]
        while queue:
            temp_node = queue.pop(0)
            # 判断传入结点的值和当前子树结点的值关系
            if node.val < temp_node.val:
                if temp_node.left is None:
                    temp_node.left = node
                    return
                else:
                    queue.append(temp_node.left)
            if node.val >= temp_node.val:
                if temp_node.right is None:
                    temp_node.right = node
                    return
                else:
                    queue.append(temp_node.right)

    # 中序遍历
    def in_order(self, node):
        if node is None:
            return
        self.in_order(node.left)
        print(node.val, end=" ")
        self.in_order(node.right)

    # 删除节点
    def del_node(self, node, val):
        '''
        :param node: 传入根结点
        :param val: 传入要删除结点的值
        :return:
        '''
        if node is None:
            return
        # 先去找到要删除的结点
        target_node = self.search(node, val)
        if target_node is None:  # 如果没有找到要删除的结点
            return
        # 如果发现当前这棵二叉排序树只有一个结点
        if node.left is None and node.right is None:
            self.root = None # 根结点直接置空
            return
        # 去找到target_node的父结点
        parent = self.parent(node, val)
        # 删除的结点是叶子结点
        if target_node.left is None and target_node.right is None:
            # 判断target_node 是父结点的左子结点,还是右子结点
            if parent.left and parent.left.val == val:  # target_node 是左子结点
                parent.left = None
            elif parent.right and parent.right.val == val:  # target_node 是右子结点
                parent.right = None
        elif target_node.left and target_node.right:  # 删除有两颗子树的结点
            min_val = self.del_right_tree_min(target_node.right)
            target_node.val = min_val
        else:  # 删除只有一颗子树的结点
            if target_node.left:  # 如果要删除的结点target_node有左子结点
                if parent: # 如果target_node有父结点
                    if parent.left.val == val:  # target_node是parent左子结点
                        parent.left = target_node.left
                    else:  # parent.right.val == val,即是target_node是parent右子结点
                        parent.right = target_node.left
                else:
                    self.root = target_node.left
            else:  # 如果要删除的结点target_node有右子结点
                if parent: # 如果target_node有父结点
                    if parent.left.val == val:
                        parent.left = target_node.right
                    else:  # parent.right.val == val,即是target_node是parent右子结点
                        parent.right = target_node.right
                else:
                    self.root = target_node.right

    # 查找结点
    def search(self, node, val):
        '''
        :param node: 传入根结点
        :param val: 传入要查找的值
        :return: 找到返回该值,没找到返回None
        '''
        if node is None:
            return None
        if node.val == val:
            return node
        if val < node.val:
            return self.search(node.left, val)
        else:
            return self.search(node.right, val)

    # 查找结点的父结点
    def parent(self, node, val):
        '''
        :param node: 传入根结点
        :param val: 传入要找的父结点的值
        :return: 如果找到返回该父结点,如果没有返回None
        '''
        if node is None:  # 如果要找的值遍历完二叉树还不存在,由此退出并返回None
            return None
        if self.root.val == val:  # 根结点没有父结点
            return None
        # 如果当前结点的左子结点或者右子结点存在,并且值就是要要找的,直接返回它的父结点
        if (node.left and node.left.val == val) or (node.right and node.right.val == val):
            return node
        else:
            # 如果要找的结点值小于父结点且它的左子结点存在,向左递归
            if val < node.val and node.left:
                return self.parent(node.left, val)
            # 如果要找的结点值大于父结点且它的右子结点存在,向左递归
            elif node.val < val and node.right:
                return self.parent(node.right, val)

    def del_right_tree_min(self, node):
    	# 从target_node的右子树出发,查找它的左边最小结点,并返回删除结点的值
    	# 作用1:返回以node为根结点的二叉排序树的最小结点
    	# 作用2:删除 node 为根结点的二叉排序树的最小结点
        temp_node = node
        # 循环的查找左结点,直到找到最小值
        while temp_node.left:
            temp_node = temp_node.left
        # 这时 target就指向了最小结点
        # 调用删除方法,删除最小结点
        self.del_node(self.root, temp_node.val) # 注意传入的还是跟结点,从根结点开始查找
        return temp_node.val


if __name__ == '__main__':
    t = BinarySortTree()
    note_array = [7, 3, 10, 12, 5, 1, 9, 2]
    for item in note_array:
        t.add(item)
    '''# 测试:删除叶子结点
    t.del_node(t.root, 2)
    t.del_node(t.root, 5)
    t.del_node(t.root, 9)
    t.del_node(t.root, 12)
    t.in_order(t.root) # 1 3 7 10
    '''

    '''# 测试:删除只有一颗子树的结点
    t.del_node(t.root, 1)
    t.in_order(t.root) # 2 3 5 7 9 10 12 
    '''
    # 测试:删除有两颗子树的结点
    # t.del_node(t.root, 7)
    # t.in_order(t.root) # 1 2 3 5 9 10 12
    # t.del_node(t.root, 10)
    # t.in_order(t.root)  # 1 2 3 5 7 9 12
    # t.in_order(t.root)

    # 连续删除任意结点测试:
    t.del_node(t.root, 2)
    t.del_node(t.root, 5)
    t.del_node(t.root, 9)
    t.del_node(t.root, 12)
    t.del_node(t.root, 7)
    # t.del_node(t.root, 3)
    # t.del_node(t.root, 10)
    # t.del_node(t.root, 1)
    t.in_order(t.root)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值