Python 实现二叉树的创建、二叉树的添加、二叉树的删除、二叉树的修改、二叉树的查找、二叉树的的遍历 最详细的二叉树 增 删 改 查

二叉树的创建、添加和遍历

  • 因为我之前文章>>>二叉树详解 已经详细写了二叉树的创建以及二叉树的广度和深度遍历,这里就不重复叙述实现过程,直接将代码规范书写如下:
    在这里插入图片描述
class TreeNote(object): # 创建树的结点
    def __init__(self, val=-1):
        self.val = val
        self.left = None
        self.right = None


class BinaryTree(object): # 创建二叉树
    def __init__(self):
        self.root = None # 根结点

    def add(self, val):  # 二叉树添加结点
        node = TreeNote(val)
        if self.root is None:
            self.root = node
            return
        queue = [self.root]
        while queue:
            temp_node = queue.pop(0)
            if temp_node.left is None:
                temp_node.left = node
                return
            else:
                queue.append(temp_node.left)
            if temp_node.right is None:
                temp_node.right = node
                return
            else:
                queue.append(temp_node.right)

    def bre_order(self, node):  # 二叉树的广度遍历
        if node is None:
            return
        queue = [node]
        while queue:
            temp_node = queue.pop(0)
            print(temp_node.val, end=" ")
            if temp_node.left is not None:
                queue.append(temp_node.left)
            if temp_node.right is not None:
                queue.append(temp_node.right)

    '''递归实现二叉树的三种深度遍历'''
    # def pre_order(self, node):  # 二叉树的前序遍历(递归)
    #     if node is None:
    #         return
    #     print(node.val, end=" ")
    #     self.pre_order(node.left)
    #     self.pre_order(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 post_order(self, node): # 二叉树的后序遍历(递归)
    #     if node is None:
    #         return
    #     self.post_order(node.left)
    #     self.post_order(node.right)
    #     print(node.val, end=" ")

    '''非递归实现二叉树的三种深度遍历'''
    def pre_order(self, node):
        if node is None:
            return
        stack = []
        temp_node = node
        while temp_node or stack:
            while temp_node:
                print(temp_node.val, end=" ")
                stack.append(temp_node)
                temp_node = temp_node.left
            node = stack.pop()
            temp_node = node.right

    def in_order(self, node):
        if node is None:
            return
        stack = []
        temp_node = node
        while temp_node or stack:
            while temp_node:
                stack.append(temp_node)
                temp_node = temp_node.left
            node = stack.pop()
            print(node.val, end=" ")
            temp_node = node.right

    def post_order(self, node):  # 二叉树的后序遍历(非递归)
        if node is None:
            return None
        stack = []
        temp_node = node
        while temp_node or stack:
            while temp_node:
                stack.append(temp_node)
                temp_node = temp_node.left
            left_node = stack[-1]
            temp_node = left_node.right
            if temp_node is None:
                node = stack.pop()
                print(node.val, end=" ")
                while stack and node == stack[-1].right:
                    node = stack.pop()
                    print(node.val, end=" ")


if __name__ == '__main__':
    t = BinaryTree()
    for i in range(10):
        t.add(i)
    print("\n广度遍历为:")
    t.bre_order(t.root)
    print("\n前序遍历为:")
    t.pre_order(t.root)
    print("\n中序遍历为:")
    t.in_order(t.root)
    print("\n后序遍历为:")
    t.post_order(t.root)
    
'''
广度遍历为:
0 1 2 3 4 5 6 7 8 9 
前序遍历为:
0 1 3 7 8 4 9 2 5 6 
中序遍历为:
7 3 8 1 9 4 0 5 2 6 
后序遍历为:
7 8 3 9 4 1 5 6 2 0 
'''

二叉树的查找与修改

查找指定元素的父结点

  • 还是以为这下图为例,我们先来实现如何查找到给定值的父结点
    在这里插入图片描述
  • 整体思路用的是广度遍历,一层一层的去判断,并添加每一个结点的左右子结点,然后重复判断
class TreeNode(object):
    def __init__(self, val=-1):
        self.val = val
        self.left = None
        self.right = None


class BinaryTree(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 temp_node.left is None:
                temp_node.left = node
                return
            else:
                queue.append(temp_node.left)
            if temp_node.right is None:
                temp_node.right = node
                return
            else:
                queue.append(temp_node.right)


    def get_parent(self, val):  # 二叉树查找父结点
        if self.root.val == val:  # 根结点没有父结点
            return None
        queue = [self.root]
        while queue:
            temp_node = queue.pop(0)
            if temp_node.left and temp_node.left.val == val:
                return temp_node
            if temp_node.right and temp_node.right.val == val:
                return temp_node
            if temp_node.left:
                queue.append(temp_node.left)
            if temp_node.right:
                queue.append(temp_node.right)
        return None


if __name__ == '__main__':
    t = BinaryTree()
    for i in range(10):
        t.add(i)
    print(t.get_parent(2).val) # 如要查找值为2的结点的父结点,结果为 0 即是根结点

查找指定值/结点、修改指定值/结点

  • 分别用广度、深度三种方式来实现查找指定值,如果找到则返回该结点,并打印该结点值,没找到则返回空
  • 分别测试查找一个指定值,所花费的次数,注意测试次数和选定的结点数值位置有关
class TreeNode(object):
    def __init__(self, val=-1):
        self.val = val
        self.left = None
        self.right = None


class BinaryTree(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 temp_node.left is None:
                temp_node.left = node
                return
            else:
                queue.append(temp_node.left)
            if temp_node.right is None:
                temp_node.right = node
                return
            else:
                queue.append(temp_node.right)

    def bre_search(self, val):  # 二叉树广度查找
    	print("进入广度查找") # 进入,需要直接比较根结点
        if self.root.val == val:
            return self.root
        queue = [self.root]
        while queue:
            temp_node = queue.pop(0)
            print("进入广度查找") # 注意计算比较次数的位置
            if temp_node.left and temp_node.left.val == val:
                return temp_node.left
            print("进入广度查找") # 第二条分支也应当有一个
            if temp_node.right and temp_node.right.val == val:
                return temp_node.right
            if temp_node.left:
                queue.append(temp_node.left)
            if temp_node.right:
                queue.append(temp_node.right)
        return None

    def pre_search(self, node, val):  # 二叉树前序查找(递归)
        if node is None:
            return
        print("进入前序查找") # 比较次数进入位置
        if node.val == val:
            return node
        left_part = self.pre_search(node.left, val)
        if left_part:
            return left_part
        right_part = self.pre_search(node.right, val)
        if right_part:
            return right_part
        return None

    def in_search(self, node, val):  # 二叉树中序查找(递归)
        if node is None:
            return
        left_part = self.in_search(node.left, val)
        if left_part:
            return left_part
        print("进入中序查找") # 从这里开始计算比较
        if node.val == val:
            return node
        right_part = self.in_search(node.right, val)
        if right_part:
            return right_part
        return None

    def post_search(self, node, val):  # 二叉树后序查找(递归)
        if node is None:
            return
        left_part = self.post_search(node.left, val)
        if left_part:
            return left_part
        right_part = self.post_search(node.right, val)
        if right_part:
            return right_part
        print("进入后序查找") # 从这里开始计算比较
        if node.val == val:
            return node
        return None


if __name__ == '__main__':
    t = BinaryTree()
    for i in range(10):
        t.add(i)
    # 广度查找
    bre_res = t.bre_search(4)
    if bre_res:
        print(bre_res.val)
    else:
        print(bre_res)
    # 前序查找
    pre_res = t.pre_search(t.root, 4)
    if pre_res:
        print(pre_res.val)
    else:
        print(pre_res)
    # 中序查找
    in_res = t.in_search(t.root, 4)
    if in_res:
        print(in_res.val)
    else:
        print(in_res)
    # 后序查找
    post_res = t.post_search(t.root, 4)
    if post_res:
        print(post_res.val)
    else:
        print(post_res)
'''输出结果:
进入广度查找
进入广度查找
进入广度查找
进入广度查找
进入广度查找
4
进入前序查找
进入前序查找
进入前序查找
进入前序查找
进入前序查找
进入前序查找
4
进入中序查找
进入中序查找
进入中序查找
进入中序查找
进入中序查找
进入中序查找
4
进入后序查找
进入后序查找
进入后序查找
进入后序查找
进入后序查找
4
'''
  • 上述示例以查找结点4值为4,比较四种遍历方式所花费次数,广度遍历 依次为:[0,1,2,3,4] 所以是5次,分别在根结点,左右子结点处发生比较;前序遍历依 次为[0,1,3,7,8,4] 所以是6次;中序遍历 依次为:[7,3,8,1,9,4] 所以是6次;后序遍历 依次为:[7,8,3,9,4] 所以是5次,可以对比下图,去验证一下!
    在这里插入图片描述
  • 关于二叉树的修改和二叉树查找原理是一样的,只需要用四种查找方式的一种先找到要修改的结点,然后返回该结点,把新的值赋值给该结点的val就可以了,这里就不加赘述了!

二叉树的删除

  • 二叉树的删除,真正的操作是在二叉搜索树的基础上来实现的,至于二叉搜索树(二叉排序树)的删除会另开文章详解

  • 这里仅叙述二叉树如何删除节点,而且规定:

  • 如要要删除非叶子结点,就把它的左右子树都删除,即:如果要删的不是非叶子结点,删除它就连同它的左右子树一起删除;这是因为二叉树通常“指向”都是从根指向叶子,只能去找它的左右子树结点,而无法去找它的“根结点”(下面这种情况,通过写一个方式可以找各个“根结点”);这种情况用递归能很好完成!

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


class BinaryTree(object):
    def __init__(self):
        self.root = None
        self.flag = False # 主函数输出判断

    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 temp_node.left is None:
                temp_node.left = node
                return
            else:
                queue.append(temp_node.left)
            if temp_node.right is None:
                temp_node.right = node
                return
            else:
                queue.append(temp_node.right)

    def pre_oreder(self, node):  # 用前序遍历来测试 删除前和删除后的数据
        if node is None:
            return
        stack = []
        temp_node = node
        while temp_node or stack:
            while temp_node:
                print(temp_node.val, end=" ")
                stack.append(temp_node)
                temp_node = temp_node.left
            node = stack.pop(-1)
            temp_node = node.right

    def del_val(self, node, val):
        if node is None:
            return
        if node.val == val and node == self.root: # 如果删除的是根结点,直接置空,然后退出
            self.root = None
            return
        if node.val == val: # 找到了该结点,将当前结点左右置空,然后返回该结点的值
            node.left = None
            node.right = None
            return node.val # 返回结点值来提供判断条件,如果有返回值,说明找到了,没有则没找到
        left_part = self.del_val(node.left, val)
        if left_part: # 如果左侧有返回值,说明找到了,将当前层的结点的左侧置为空即可
        	self.flag = True
            node.left = None
        right_part = self.del_val(node.right, val) # 如果左侧递归到最后一个左结点,返回值还是空,就从左侧最后一层,开始向右递归
        if right_part:
        	self.flag = True
            node.right = None
        return None # 如果遍历完二叉树,发现都没找到,说明要删除的值二叉树不存在


if __name__ == '__main__':
    t = BinaryTree()
    for i in range(10):
        t.add(i)
    print("删除前:")
    t.pre_oreder(t.root)
    print()
    del_res = t.del_val(t.root, 1)
    # del_res = t.del_val(t.root, 16) # "要删除的值,二叉树中不存在"
    # del_res = t.del_val(t.root, 0)  # "删除根结点,二叉树置空"
    if del_res == -1:
        print("删除根结点,二叉树置空")
    elif t.flag:
        print("删除后:")
        t.pre_oreder(t.root)
    elif not t.flag:
        print("要删除的值,二叉树中不存在")
'''
删除前:
0 1 3 7 8 4 9 2 5 6 
删除后:
0 2 5 6 
'''
'''
可以任意输入一个要删除的不存在二叉树的值,会返回"要删除的值,二叉树中不存在"
'''

在这里插入图片描述

  • 如果不删除二叉树的根结点(如果删除根结点,需要按照二叉搜索树的变换规则),这里规定不删除二叉树的第一个结点,那么可以这样实现:

    (1)关键是 先获取 待删除节点值 val 的父节点,上面查找里已经写了获取父结点的方法,这里直接拿来用就可以了!具体操作过程如下:
    在这里插入图片描述

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


class BinaryTree(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 temp_node.left is None:
                temp_node.left = node
                return
            else:
                queue.append(temp_node.left)
            if temp_node.right is None:
                temp_node.right = node
                return
            else:
                queue.append(temp_node.right)

    def pre_oreder(self, node):  # 用前序遍历来测试 删除前和删除后的数据
        if node is None:
            return
        stack = []
        temp_node = node
        while temp_node or stack:
            while temp_node:
                print(temp_node.val, end=" ")
                stack.append(temp_node)
                temp_node = temp_node.left
            node = stack.pop(-1)
            temp_node = node.right

    def get_parent(self, val):  # 二叉树查找父结点
        if self.root.val == val:  # 根结点没有父结点
            return None
        queue = [self.root]
        while queue:
            temp_node = queue.pop(0)
            if temp_node.left and temp_node.left.val == val:
                return temp_node
            if temp_node.right and temp_node.right.val == val:
                return temp_node
            if temp_node.left:
                queue.append(temp_node.left)
            if temp_node.right:
                queue.append(temp_node.right)
        return None

    def del_val(self, val):
        if self.root is None:  # 如果根为空,直接返回
            return False
        parent = self.get_parent(val)  # 获取到要删除节点值得父结点
        if parent:
            del_node = parent.left if parent.left.val == val else parent.right  # 待删除节点
            if del_node.left is None:  # 左子树为空
                if parent.left.val == val:
                    parent.left = del_node.right
                else:
                    parent.right = del_node.right
                del del_node
                return True
            elif del_node.right is None:  # 右子树为空
                if parent.left.val == val:
                    parent.left = del_node.left
                else:
                    parent.right = del_node.left
                del del_node
                return True
            else:  # 左右子树都不为空
                tmp_pre = del_node
                tmp_next = del_node.right
                if tmp_next.left is None:
                    # 替代
                    tmp_pre.right = tmp_next.right
                    tmp_next.left = del_node.left
                    tmp_next.right = del_node.right
                else:
                    while tmp_next.left:  # 让tmp指向右子树的最后一个叶子
                        tmp_pre = tmp_next
                        tmp_next = tmp_next.left
                    # 替代
                    tmp_pre.left = tmp_next.right
                    tmp_next.left = del_node.left
                    tmp_next.right = del_node.right
                if parent.left.val == val:
                    parent.left = tmp_next
                else:
                    parent.right = tmp_next
                del del_node
                return True
        else:
            return False


if __name__ == '__main__':
    t = BinaryTree()
    for i in range(10):
        t.add(i)
    print("删除前:")
    t.pre_oreder(t.root)
    print()
    print(t.del_val(4))
    print("删除后:")
    t.pre_oreder(t.root)
    
''' 输出结果:可以对照上面的图比较下
删除前:
0 1 3 7 8 4 9 2 5 6 
True
删除后:
0 1 3 7 8 9 2 5 6 
'''
发布了146 篇原创文章 · 获赞 37 · 访问量 7859

猜你喜欢

转载自blog.csdn.net/storyfull/article/details/103717740