基于Python3的数据结构与算法 - 19 二叉搜索树

目录

一、二叉搜索树

1、二叉搜索树的插入

2、二叉搜索树的查找

3. 二叉搜素树的删除


一、二叉搜索树

  • 二叉搜索树是一颗二叉树且满足性质:设x是二叉树的一个节点。如果y是x左子树的一个节点,那么y.key <= x.key ; 如果y是x右子树的一个节点,那么y.key > = x.key.
  • 二叉搜索树的操作:查询、插入、删除(查询和插入的时间复杂度为logn)

1、二叉搜索树的插入

示例代码如下:

class BirTreeNode:
    def __init__(self, data):
        self.data = data
        self.lchild = None  # 左孩子
        self.rchild = None  # 右孩子
        self.parent = None  # 父节点;相当于双链表


class BST:
    def __init__(self, li = None):
        self.root = None
        # self.root = None
        if li:
            for val in li:
                self.insert_no_rec(val)

    def insert(self, node, val):  # 插入函数(递归写法);node为当前插入的根节点
        node = BirTreeNode(node)
        if not node:  # 如果node为空
            node = BirTreeNode(val)
        elif val < node.data:  # 根节点比val大,插入左节点
            node.lchild = self.insert(node.lchild, val)
            node.lchild.parent = node
        elif val > node.data:  # 根节点比val大,此时node.rchild为根节点
            node.rchild = self.insert(node.rchild, val)
            node.rchild.parent = node
        return node
        # 如果等于,此时插入左边或右边都可以,默认没有等于这种情况
    def insert_no_rec(self ,val):  # 插入函数(非递归)
        p = self.root  #跟节点
        if not p:
            self.root = BirTreeNode(val)   # 空树
            return
        while True:
            if val < p.data:   # 往左子树走
                if p.lchild:   # p的左子树存在
                    p = p.lchild  # 根节点为左子树的孩子
                else:
                    p.lchild = BirTreeNode(val)
                    p.lchild.parent = p
            elif val > p.data:   #往右子树走
                if p.rchild:
                    p = p.rchild
                else:
                    p.rchild = BirTreeNode(val)
                    p.rchild.parent = p
            else:
                return

    def pre_order(self, root):
        if root:  # 如果root不为空
            print(root.data, end=",")
            self.pre_order(root.lchild)
            self.pre_order(root.rchild)

    # 中序遍历
    def in_order(self,root):
        if root:
            self.in_order(root.lchild)
            print(root.data, end=',')
            self.in_order(root.rchild)

    # 后序遍历
    def post_order(self, root):
        if root:
            self.post_order(root.lchild)
            self.post_order(root.rchild)
            print(root.data, end=",")
        

tree = BST([4,6,7,9,2,1,3,5,8])
tree.post_order(tree.root)
print("")
tree.in_order(tree.root)
print("")
tree.post_order(tree.root)

输出结果如下所示:我们可以发现,中序遍历的结果一定是升序的!(对于二叉搜索树来说),因为中序遍历的遍历规则为先遍历左边,再遍历根节点,再遍历右边。 

2、二叉搜索树的查找

示例代码如下:

    def query(self, node, val):  # 查询函数(递归版)
        if not node:
            return None
        if node.data < val:  # 右边找
            return self.query(node.rchild, val)  # 往右边查找
        elif node.data > val:
            return self.query(node.lchild, val)
        return node

    def query_no_rec(self, val):  # 查询函数(非递归版)
        p = self.root
        while p:
            if p.data < val:
                p = p.rchild
            elif p.data > val:
                p = p.lchild
            else:
                return p
        return None

3. 二叉搜素树的删除

 删除操作分三种情况:

  1. 如果要删除的节点是叶子节点:直接删除

2. 如果要删除的节点只有一个孩子:将此节点的父亲与孩子连接,然后删除该节点。

此时如果要删除的节点是根,那么将子节点作为新根。 

3. 如果要删除的节点有两个孩子:将该节点删除,并其右子树的最小节点(该节点最多有一个右孩子)替换当前节点。

删除操作的代码示例如下:

    def __remove_node_1(self, node):  # 情况1,删除的点为叶子节点时
        if not node.parent:  # 这个树只有一个节点,既是叶子节点也是根节点
            self.root = None
        if node == node.parent.lchild:  # node是左孩子
            node.parent.lchild = None
        else:
            node.parent.rchild = None

    def __remove_node_2_1(self, node):  # 情况2_1,node只有一个左孩子
        if not node.parent:  # 判断是否为根节点
            self.root = node.lchild
            node.lchild.parent = None
        elif node == node.parent.lchild:  # node为左孩子
            node.parent.lchild = node.lchild  # 爷孙相连
            node.lchild.parent = node.parent
        else:
            node.parent.rchild = node.lchild  # node为右孩子
            node.parent.rchild = node.parent

    def __remove_node_2_2(self, node):  # node只有一个右孩子
        if not node.parent:
            self.root = node.rchild
        elif node == node.parent.lchild:  # node为左孩子
            node.parent.lchild = node.rchild
            node.rchild.parent = node.parent
        else:
            node.parent.rchild = node.rchild
            node.rchild.parent = node.parent

    def delete(self, val):  # 因为删除操作有三种情况,因此在写删除操作之前需要先将其他集几种情况写下来
        if self.root:  # 不是空树
            node = self.query_no_rec(val)  # 先查询到要删除的节点
            if not node:  # node不存在
                return False
            if not node.lchild and not node.rchild:  # 既没有左孩子也没有右孩子,即删除的节点为叶子节点
                self.__remove_node_1(node)
            elif not node.rchild:  # 只有左孩子,2_1
                self.__remove_node_2_1(node)
            elif not node.lchild:  # 只有右孩子
                self.__remove_node_2_2(node)
            else:  # 情况三:有两个子节点,将该节点删除,将右子树的最小节点替换至该节点
                min_node = node.rchild  # 从右子树开始寻找
                while min_node.lchild:  # 一直往左走,走到头就找到最小节点
                    min_node = min_node.lchild  # 循环结束找到最小节点
                node.data = min_node.data  # 将min的最小值替换到节点位置
                # 接下来将min_node删除,此时min_node有三种删除情况,但是min_node肯定没有左孩子,只能是叶子节点或只有一个右孩子
                if min_node.rchild:
                    self.__remove_node_2_2(min_node)
                else:
                    self.__remove_node_1(min_node)

  • 15
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一道秘制的小菜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值