二叉树;二叉树的前序、中序、后序遍历及查找;顺序存储二叉树;线索化二叉树

数组、链表和树存储方式分析

对于树结构,不论是查找修改还是增加删除,效率都比较高,结合了链表和数组的优点,如以下的二叉树:

1、数组的第一个元素作为第一个节点

2、数组的第二个元素3比7小,放在7的左边

3、数组的第三个元素10比7大,放在7的右边

4、数组的第四个元素1比7小,也比3小,放在3的左边

5、数组的第五个元素5比7小,但比3大,放在3的右边

6、数组的第六个元素9比7大,但比10小,放在10的左边

7、数组的第七个元素12比7大,比10大,放在10的右边

二叉树的前中后序遍历

思路分析

代码实现

# 创建 HeroNode 节点
class HeroNode:
    def __init__(self, no: int, name: str):
        self.no = no
        self.name = name
        self.left = None
        self.right = None

    def __str__(self):
        return f"no={self.no}, name={self.name}"

    # 前序遍历
    def pre_order(self):
        # 先输出父节点
        print(self, end=' => ')
        # 左子树不为空则递归左子树
        if self.left is not None:
            self.left.pre_order()
        # 右子树不为空则递归右子树
        if self.right is not None:
            self.right.pre_order()

    # 中序遍历
    def infix_order(self):
        # 左子树不为空则递归左子树
        if self.left is not None:
            self.left.infix_order()
        # 输出父节点
        print(self, end=' => ')
        # 右子树不为空则递归右子树
        if self.right is not None:
            self.right.infix_order()

    # 后序遍历
    def post_order(self):
        # 左子树不为空则递归左子树
        if self.left is not None:
            self.left.post_order()
        # 右子树不为空则递归右子树
        if self.right is not None:
            self.right.post_order()
        # 输出父节点
        print(self, end=' => ')


# 建立 HeroNode 二叉树
class BinaryTree:
    root: HeroNode = None

    # 前序遍历
    def pre_order(self):
        if self.root is not None:
            self.root.pre_order()
        else:
            print("二叉树为空...")

    # 前序遍历
    def infix_order(self):
        if self.root is not None:
            self.root.infix_order()
        else:
            print("二叉树为空...")

    # 前序遍历
    def post_order(self):
        if self.root is not None:
            self.root.post_order()
        else:
            print("二叉树为空...")


def test_binary_tree():
    # 手动创建二叉树
    binary_tree = BinaryTree()
    root = HeroNode(1, '宋江')
    node2 = HeroNode(2, '吴用')
    node3 = HeroNode(3, '卢俊义')
    node4 = HeroNode(4, '林冲')

    root.left = node2
    root.right = node3
    node3.right = node4
    binary_tree.root = root

    # 前序
    print("前序遍历:", end=" ")
    binary_tree.pre_order()
    print()

    # 中序
    print("中序遍历:", end=" ")
    binary_tree.infix_order()
    print()

    # 后序
    print("后序遍历:", end=" ")
    binary_tree.post_order()
    print()


test_binary_tree()

二叉树的前中后序查找

思路分析

代码实现

""" 前中后序遍历查找 """
# 创建 HeroNode 节点
class HeroNode:
    def __init__(self, no: int, name: str):
        self.no = no
        self.name = name
        self.left = None
        self.right = None

    def __str__(self):
        return f"no={self.no}, name={self.name}"

    # 前序遍历查找
    def pre_order_search(self, no: int):
        """
        前序遍历查找某个节点
        :param no: 要查找节点的 id
        :return: 找到的 HeroNode 节点或 None
        """
        print("进入前序遍历...")
        if self.no == no:  # 如果当前节点是,直接返回
            return self

        find_node = None
        # 如果左子节点不为空,则向左子节点继续递归查找
        # 找到则返回,找不到则看右子节点
        if self.left is not None:
            find_node = self.left.pre_order_search(no)

        if find_node:  # 说明在左子树上找到,直接返回
            return find_node

        # 否则判断右子节点,若不为空,向右子树递归查找
        if self.right is not None:
            find_node = self.right.pre_order_search(no)

        # 如果右子树找到,则find_node有值,否则find_node为空
        return find_node

    # 中序遍历查找
    def infix_order_search(self, no: int):
        """
        中序遍历查找某个节点
        :param no: 要查找节点的 id
        :return: 找到的 HeroNode 节点或 None
        """
        find_node = None
        # 如果左子节点不为空,则向左子节点继续递归查找
        # 找到则返回,找不到则看右子节点
        if self.left is not None:
            find_node = self.left.infix_order_search(no)

        if find_node:  # 说明在左子树上找到,直接返回
            return find_node
        print("进入中序遍历...")
        if self.no == no:  # 如果当前节点是,直接返回
            return self

        # 否则判断右子节点,若不为空,向右子树递归查找
        if self.right is not None:
            find_node = self.right.infix_order_search(no)

        # 如果右子树找到,则find_node有值,否则find_node为空
        return find_node

    # 后序遍历查找
    def post_order_search(self, no: int):
        """
        后序遍历查找某个节点
        :param no: 要查找节点的 id
        :return: 找到的 HeroNode 节点或 None
        """
        find_node = None
        # 如果左子节点不为空,则向左子节点继续递归查找
        # 找到则返回,找不到则看右子节点
        if self.left is not None:
            find_node = self.left.post_order_search(no)

        if find_node:  # 说明在左子树上找到,直接返回
            return find_node

        # 否则判断右子节点,若不为空,向右子树递归查找
        if self.right is not None:
            find_node = self.right.post_order_search(no)

        # 如果右子树找到,则find_node有值,否则find_node为空
        if find_node:
            return find_node
        print("进入后序遍历...")
        if self.no == no:  # 如果当前节点是,直接返回
            return self
        return None


# 建立 HeroNode 二叉树
class BinaryTree:
    root: HeroNode = None

    # 前序查找
    def pre_order_search(self, no):
        if self.root is not None:
            return self.root.pre_order_search(no)
        else:
            return None

    # 中序查找
    def infix_order_search(self, no):
        if self.root is not None:
            return self.root.infix_order_search(no)
        else:
            return None

    # 后序查找
    def post_order_search(self, no):
        if self.root is not None:
            return self.root.post_order_search(no)
        else:
            return None


def test_binary_tree():
    # 手动创建二叉树
    binary_tree = BinaryTree()
    root = HeroNode(1, '宋江')
    node2 = HeroNode(2, '吴用')
    node3 = HeroNode(3, '卢俊义')
    node4 = HeroNode(4, '林冲')
    node5 = HeroNode(5, "关胜")

    root.left = node2
    root.right = node3
    node3.right = node4
    node3.left = node5
    binary_tree.root = root

    print("前序遍历查找:")  # 比较了4次(看输出得到的结果)
    res = binary_tree.pre_order_search(5)
    if res:
        print("找到了,节点信息为:", res)
    else:
        print("找不到编号为5的节点")
    print()

    print("中序遍历查找:")  # 比较了3次(看输出得到的结果)
    res = binary_tree.infix_order_search(5)
    if res:
        print("找到了,节点信息为:", res)
    else:
        print("找不到编号为5的节点")
    print()

    print("后序遍历查找:")  # 比较了2次(看输出得到的结果)
    res = binary_tree.post_order_search(5)
    if res:
        print("找到了,节点信息为:", res)
    else:
        print("找不到编号为5的节点")


test_binary_tree()

二叉树删除节点

思路分析

代码实现

""" 递归删除二叉树节点 """
# HeroNode 节点
class HeroNode:
    def __init__(self, no: int, name: str):
        self.no = no
        self.name = name
        self.left = None
        self.right = None

    def __str__(self):
        return f"no={self.no}, name={self.name}"

    # 前序遍历
    def pre_order(self):
        # 先输出父节点
        print(self, end=' => ')
        # 左子树不为空则递归左子树
        if self.left is not None:
            self.left.pre_order()
        # 右子树不为空则递归右子树
        if self.right is not None:
            self.right.pre_order()

    def delete_node(self, no: int):
        """
        递归删除节点规则:
            如果删除的节点是叶子节点,则直接删除
            如果删除的节点不是叶子节点,则删除该节点及其左右子树
        :param no: 要删除的节点编号
        :return:
        """
        # 如果左子节点不为空,且左子节点是要删除的节点,则删除左子节点及其子树,并返回
        if self.left and self.left.no == no:
            self.left = None  # 相当于删除左子节点及其子树
            return
        # 如果右子节点不为空,且右子节点是要删除的节点,则删除右子节点及其子树,并返回
        if self.right and self.right.no == no:
            self.right = None  # 相当于删除右子节点及其子树
            return
        # 如果左右子节点都不是要删除的节点,则首先向左子节点递归删除
        if self.left:
            self.left.delete_node(no)
        # 如果递归完左子节点还没找到要删除的节点,则继续向右子节点递归删除
        if self.right:
            self.right.delete_node(no)



# 建立 HeroNode 二叉树
class BinaryTree:
    root: HeroNode = None

    # 前序遍历
    def pre_order(self):
        if self.root is not None:
            self.root.pre_order()
        else:
            print("二叉树为空...")

    # 删除树节点
    def delete_node(self, no: int):
        if self.root:
            if self.root.no == no:  # 如果根节点是要删除的节点
                self.root = None  # 则把根节点置空
            else:
                self.root.delete_node(no)
        else:
            print("树空,不能删除节点...")


def test_binary_tree():
    # 手动创建二叉树
    binary_tree = BinaryTree()
    root = HeroNode(1, '宋江')
    node2 = HeroNode(2, '吴用')
    node3 = HeroNode(3, '卢俊义')
    node4 = HeroNode(4, '林冲')
    node5 = HeroNode(5, "关胜")

    root.left = node2
    root.right = node3
    node3.right = node4
    node3.left = node5
    binary_tree.root = root

    print("删除前:", end='')
    binary_tree.pre_order()
    print()

    binary_tree.delete_node(5)
    print("删除后:", end='')
    binary_tree.pre_order()
    print()



test_binary_tree()

顺序存储二叉树

思路分析

代码实现

需求如下:

"""顺序存储二叉树"""
# 顺序存储二叉树就是用数组结构存储二叉树节点数据,
# 要求用数组存储后,可以对该数组进行前序遍历、中序遍历、后序遍历
# 其实就是将二叉树从左到右,从上到下的节点依次存入数组中,如下:
"""
假设有如下一棵二叉树,它对应的顺序存储就是:arr = [1, 2, 3, 4, 5, 6, 7]
                1
             2      3
          4    5  6    7
"""
class ArrayBinaryTree:
    def __init__(self, arr):
        self.arr = arr

    def pre_order(self, index: int):
        """
        以前序遍历方式访问数组元素
        :param index: 数组下标
        :return:
        """
        n = len(self.arr)  # n为数组长度
        if self.arr and n > 0:
            # 输出当前元素
            print(f"arr[{index}]={self.arr[index]}", end=" ")
            # 向左子树递归
            if 2 * index + 1 < n:
                self.pre_order(2 * index + 1)
            # 向右子树递归
            if 2 * index + 2 < n:
                self.pre_order(2 * index + 2)
        else:
            print("数组为空!")

    def infix_order(self, index: int):
        """
        以中序遍历方式访问数组元素
        :param index: 数组下标
        :return:
        """
        n = len(self.arr)
        if self.arr and n > 0:
            if 2 * index + 1 < n:  # 向左子树递归
                self.infix_order(2 * index + 1)
            print(f"arr[{index}]={self.arr[index]}", end=" ")
            if 2 * index + 2 < n:  # 向右子树递归
                self.infix_order(2 * index + 2)
        else:
            print("数组为空")

    def post_order(self, index: int):
        """
        以后序遍历方式访问数组元素
        :param index: 数组下标
        :return:
        """
        n = len(self.arr)
        if self.arr and n > 0:
            if 2 * index + 1 < n:  # 向左子树递归
                self.post_order(2 * index + 1)
            if 2 * index + 2 < n:  # 向右子树递归
                self.post_order(2 * index + 2)
            print(f"arr[{index}]={self.arr[index]}", end=" ")


arr_binary_tree = ArrayBinaryTree([1, 2, 3, 4, 5, 6, 7])
print("前序遍历:")
arr_binary_tree.pre_order(0)
print()
print("中序遍历:")
arr_binary_tree.infix_order(0)
print()
print("后序遍历:")
arr_binary_tree.post_order(0)
print()

线索化二叉树

简单介绍

思路分析

遍历线索化二叉树

线索化二叉树和遍历线索化二叉树的代码实现

""" 线索化二叉树 """
# 创建 Node 节点
class Node:
    no: int = None
    left = None
    right = None
    # left_type/right_type 表示指针类型
    # 值为0时表示指向的是左子树/右子树,为1时表示指向的是前驱节点/后继节点
    left_type: int = 0
    right_type: int = 0

    def __init__(self, no: int):
        self.no = no
        self.left = None
        self.right = None

    def __str__(self):
        return f"no={self.no}"


# 建立线索化 Node 二叉树
class ThreadedBinaryTree:
    root: Node = None
    # 为了实现线索化,需要一个指针(变量)指向当前节点的前驱节点
    # 如中序线索化中,需要一个指针(变量)指向当前节点在中序遍历结果中的前驱节点
    # 在递归进行线索化时, pre 总指向当前节点按某种遍历方式结果的前驱节点
    pre: Node = None

    # 建立中序线索化二叉树
    def threaded_infix_tree(self, node: Node):
        """
        建立中序线索化二叉树
        :param node: 要线索化的节点
        :return:
        """
        if node is None:  # 节点为空,不需要线索化
            return
        # 先线索化左子树
        self.threaded_infix_tree(node.left)
        # 线索化当前节点
        # 结合图形理解代码,第一个要线索化的节点是8
        # 先处理当前节点的左子节点
        if node.left is None:  # 如果当前节点的左指针为空,则让左指针指向当前节点的前驱节点pre
            node.left = self.pre
            node.left_type = 1  # 设置指针类型为1,表示该指针指向的是前驱节点
        # 处理后继节点
        if self.pre and  self.pre.right is None:
            self.pre.right = node
            self.pre.right_type = 1  # 设置指针类型为1,表示该指针指向的是后继节点
        # 每处理一个节点后,让当前节点成为下一个节点的前驱节点
        self.pre = node
        # 后线索化右子树
        self.threaded_infix_tree(node.right)

    # 遍历中序线索化二叉树
    def for_in_tree(self):
        node = self.root
        while node:
            # 循环找到 left_type = 1 的节点,该节点就是中序遍历的第一个节点,即图中的节点8
            while node.left_type == 0:
                node = node.left
            # 输出当前节点
            print(node, end=" ")
            # 如果当前节点的右指针指向的是后继节点,则一直输出
            while node.right_type == 1:
                node = node.right
                print(node, end=" ")
            # 替换要遍历的节点,具体过程通过debug和结合图来看会更容易理解
            node = node.right


def test_binary_tree():
    # 手动创建二叉树
    binary_tree = BinaryTree()
    root = Node(1)
    node2 = Node(3)
    node3 = Node(6)
    node4 = Node(8)
    node5 = Node(10)
    node6 = Node(14)

    root.left = node2
    root.right = node3
    node2.left = node4
    node2.right = node5
    node3.left = node6

    threaded_binary_tree = ThreadedBinaryTree()
    threaded_binary_tree.root = root
    # 测试线索化
    print(f"线索化前:10的left={node5.left},right={node5.right}")
    threaded_binary_tree.threaded_infix_tree(root)
    # 以10号节点,即node5测试
    print(f"线索化后:10的前驱节点={node5.left},后继节点={node5.right}")

    # 测试遍历线索化二叉树
    threaded_binary_tree.for_in_tree()


test_binary_tree()

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值