二叉搜索树基本操作实现(python)创捷 、遍历(递归、非递归)、查找、删除等

二叉搜索树基本操作实现(python)

创建 、遍历(递归、非递归)、查找、删除等(有问题请指出,谢谢哈!)

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date    : 2021-04-17
# @Author  : dwchen
# @Link    : 
# @Version : 
"""二叉搜索树BST(二叉排序树、二叉查找树)binary search tree介绍
二叉搜索树或者是一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于或等于它的根节点的值;
(2)若右子树不空,则右子树上所有结点的值均大于或等于它的根结点的值;
(3)左、右子树也分别为二叉搜索树;
"""

"""二叉搜索树基本操作
二叉搜索树创建
先序遍历(递归,迭代)
中序遍历(递归,迭代)
后序遍历(递归,迭代)
层次遍历(迭代)
查找
删除
获取树的最大深度
二叉搜索树所有路径
"""

class Stack():
    """列表实现顺序栈
    """
    def __init__(self):
        self.stack = []
        self.num = 0

    def push(self, value):  # 进栈
        self.stack.append(value)
        self.num += 1

    def pop(self):  # 出栈
        if self.stack:
            data = self.stack.pop()
            self.num -= 1
            return data
    
    def top(self):
        if self.stack:
            return self.stack[-1]


    def is_empty(self):  # 判断栈是否空
        return not bool(self.stack)


class Node():
    def __init__(self, data):
        self.data = data
        self.lchild = None
        self.rchild = None
        # self.traverse_count = 0  # 记录结点被遍历的次数,便于后序非递归遍历post_order1, 其他方法不需要这个变量


class BST():
    def __init__(self):
        self.root = None

    def create_BST(self, data_list):
        for data in data_list:
            self.root = self.insert(self.root, data)

    def insert(self, root, data):
        if root == None:
            node = Node(data)
            root = node
        elif data == root.data:
            return None
        elif data > root.data:
            root.rchild = self.insert(root.rchild, data)
        else:
            root.lchild = self.insert(root.lchild, data)
        return root


    # def insert(self, data):  # 非递归 添加节点
    #     node = Node(data)
    #     if self.root == None:
    #         self.root = node
    #     else:
    #         parent = None
    #         cur = self.root
    #         while cur != None:
    #             parent = cur
    #             if data > cur.data:
    #                 cur = cur.rchild
    #             elif data < cur.data:
    #                 cur = cur.lchild
    #             else:
    #                 pass
    #         if data > parent.data:
    #             parent.rchild = node
    #         elif data < parent.data:
    #             parent.lchild = node

    def pre_order_traverse(self, node):
        if node is not None:
            print(node.data, end=' ')
            self.in_order_traverse(node.lchild)
            self.in_order_traverse(node.rchild)

    def in_order_traverse(self, node):
        if node is not None:
            self.in_order_traverse(node.lchild)
            print(node.data, end=' ')
            self.in_order_traverse(node.rchild)

    def post_order_traverse(self, node):
        if node is not None:
            self.in_order_traverse(node.lchild)
            self.in_order_traverse(node.rchild)
            print(node.data, end=' ')

    #-----------------------------------非递归遍历------------------------------#
    # 前序、中序和后序遍历:三者的共同点是“左子节点”一定在“右子节点”之前输出,“中间根节点”则根据遍历的类型选择放在最前、中间还是最后。
    # a.遇到一个节点,访问它,然后把它压栈,并去遍历它的左子树;
    # b.当左子树遍历结束后,从栈顶弹出该节点并将其指向右儿子,继续a步骤;
    # c.当所有节点访问完即最后访问的树节点为空且栈空时,停止。
    def pre_order(self):
        T = self.root
        S = Stack()
        while T or (not S.is_empty()):
            while T:
                print(str(T.data), end=' ')
                S.push(T)
                T = T.lchild
            if not S.is_empty():
                T = S.pop()
                T = T.rchild
        print()

    # a.中序先将结点进栈,遍历到左下角尽头,
    # b.然后再出栈访问,并将其指向其右儿子,继续a步骤
    # c.当所有结点访问完即最后访问的树结点为空且栈为空时,停止
    def in_order(self):
        p = self.root  
        stack = Stack()
        while p or not stack.is_empty():
            while p:
                stack.push(p)
                p = p.lchild
            if not stack.is_empty():
                p = stack.pop()
                print(p.data, end=' ')
                p = p.rchild
        print()

    # 思路一:对于任一结点P,将其入栈,然后沿其左子树一直往下搜索
    # 直到搜索到没有左孩子结点,此时该结点出现在栈顶,但是此时不能将其出栈并访问,
    # 因为其右孩子还未被访问。 所以,接下来按照相同的规则对其右子树进行
    # 相同的处理,当遍历完其右孩子时,该结点第二次出现在栈顶,此时可以将该结点
    # 出栈并访问。这样就保证了正确的访问顺序。可以看出,每个结点都第二次出现在
    # 栈顶时,才能访问它。因此需要多设置一个变量标识该结点是第几次出现在栈顶
    def post_order1(self):
        p = self.root 
        temp = None
        stack = Stack()
        #stack.push(p)
        while p or not stack.is_empty():
            while p:
                p.traverse_count = 1
                stack.push(p)
                p = p.lchild
            if not stack.is_empty():
                temp = stack.pop()
                if temp.traverse_count == 1:
                    temp.traverse_count = 2
                    stack.push(temp)
                    p = temp.rchild
                elif temp.traverse_count == 2:
                    print(temp.data, end=' ')
        print()


    # 思路2:要保证根结点在左右孩子访问之后才能访问,因此,对于任一结点P,先将其入栈。
    # 如果P不存在左孩子和右孩子,则可以直接访问它;或者P存在左孩子或右孩子,但是其左孩子
    # 和右孩子都已经被访问过,则同样可以直接访问该结点。若非上述两种情况,则将P的右孩子和左孩子
    # 依次入栈,这样就保证每次取栈顶元素的时候,左孩子在右孩子前面被访问,左右孩子都在根结点前被访问。
    def post_order2(self):
        pre = None
        cur = self.root
        stack = Stack()
        stack.push(cur)
        while not stack.is_empty():
            cur = stack.top()
            if(cur.lchild == None and cur.rchild == None) or (pre != None and (pre == cur.lchild or pre == cur.rchild)):
                print(cur.data, end=' ')
                stack.pop()
                pre = cur
            else:
                if cur.rchild != None:
                    stack.push(cur.rchild)
                if cur.lchild != None:
                    stack.push(cur.lchild)
        print()


    # 思路3:前序遍历的访问顺序是根,左,右。而后续遍历的节结点访问顺序是左,右,根。
    # 若把前序遍历的顺序改为根,右,左。最后,将结果倒置一下,即为后序遍历的结果。
    # https://zhuanlan.zhihu.com/p/82074260
    def post_order3(self):
        p = self.root
        temp_stack = Stack()
        result_stack = Stack()
        while p or  not temp_stack.is_empty():
            while p:
                result_stack.push(p)
                temp_stack.push(p)
                p = p.rchild
            if not temp_stack.is_empty():
                p = temp_stack.pop()
                p = p.lchild
        while not result_stack.is_empty():
            temp = result_stack.pop()
            print(temp.data, end=' ')
        print()

    # 一种不常见的后序遍历方法
    # https://blog.csdn.net/alexmiaomiao/article/details/81813021
    def post_order4(self):
        stack = Stack()
        stack.push(self.root)       
        while not stack.is_empty():
            p = stack.pop()
            if type(p) is Node:
                stack.push(p.data)
                if p.rchild:
                    stack.push(p.rchild)
                if p.lchild:
                    stack.push(p.lchild)
            else:
                print(p, end=' ')
        print()

    def level_oreder(self):  #层次遍历
        queue = []  # list 模拟队列
        queue.append(self.root)
        while queue:
            node = queue.pop(0)
            print(node.data, end=' ')
            if node.lchild:
                queue.append(node.lchild)
            if node.rchild:
                queue.append(node.rchild)

    #----------------------------------非递归遍历结束-----------------------------------------------#

    #递归写法, 用层次遍历记录层数也可以
    def max_depth(self, root):
        if root is None:
            return 0
        left_depth = self.max_depth(root.lchild)
        right_depth = self.max_depth(root.rchild)
        return left_depth+1 if left_depth > right_depth else right_depth+1


    def get_all_tree_path(self):
        pass

    def search(self, value):
        cur = self.root
        while cur is not None:
            if cur.data == value:
                break
            if value > cur.data:
                cur = cur.rchild
            else:
                cur = cur.lchild
        return cur

    def search_parent(self, value):
        parent = None
        cur = self.root
        while cur is not None:
            if cur.data == value:
                break
            if value > cur.data:
                parent = cur
                cur = cur.rchild
            else:
                parent = cur
                cur = cur.lchild
        return parent

    def search_target_and_parent(self, value):
        parent = None
        cur = self.root
        while cur is not None:
            if cur.data == value:
                break
            if value > cur.data:
                parent = cur
                cur = cur.rchild
            else:
                parent = cur
                cur = cur.lchild
        return cur, parent

    def find_min(self, root):
        cur = root
        while cur.lchild:
            cur = cur.lchild
        return cur


    # 删除指定结点,需要分如下几种情况:
    # 删除非根节点
    # 1.待删除结点没有孩子(即:叶节点)
    # 2.待删除结点只有一个孩子(左孩子或者右孩子)
    # 3.待删除结点有两个孩子
    # 删除根节点
    # 1.待删除结点没有孩子(即:叶节点)
    # 2.待删除结点只有一个孩子(左孩子或者右孩子)
    # 3.待删除结点有两个孩子
    # https://blog.csdn.net/qq_45783660/article/details/115320477
    def remove(self, value):
        target, parent = self.search_target_and_parent(value)      
        if parent:  # 删除非 根节点, 根节点的parent为 None
            if target.lchild is None and target.rchild is None:
                if target == parent.lchild:
                    parent.lchild = None
                if target == parent.rchild:
                    parent.rchild = None
            elif target.lchild is not None and target.rchild is not None:
                right_min_node = self.find_min(target.rchild)
                temp = right_min_node.data
                self.remove(temp)
                target.data = temp
            else:
                if target.lchild is None and target.rchild is not None:
                    if target == parent.lchild:
                        parent.lchild = target.rchild
                    if target == parent.rchild:
                        parent.rchild = target.rchild
                if target.lchild is not None and target.rchild is None:
                    if target == parent.lchild:
                        parent.lchild = target.lchild
                    if target == parent.rchild:
                        parent.rchild = target.lchild   
        else:  # 删除 根节点
            if target.lchild is None and target.rchild is None:
                self.root = None
            elif target.lchild is not None and target.rchild is not None:
                self.root.lchild.rchild = self.root.rchild
                self.root = self.root.lchild
            else:
                if target.lchild is None and target.rchild is not None:
                    self.root = self.root.rchild
                if target.lchild is not None and target.rchild is None:
                    self.root = self.root.lchild




if __name__ == "__main__":
    a = [1, 2, 9, 6, 7]
    bst = BST()
    bst.create_BST(a)
    #bst.in_order_traverse(bst.root)
    # bst.pre_order()
    # bst.in_order()
    # bst.post_order1()
    # bst.post_order2()
    # bst.post_order3()
    # bst.post_order4()
    # bst.level_oreder()
    # max_depth = bst.max_depth(bst.root)
    # print(max_depth)
    # bst.search(1)
    # bst.search(3)
    bst.remove(1)
    bst.in_order()

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值