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

news2024/11/21 2:34:37

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

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

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()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1119947.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Win10系统2023年10月更新补丁(KB5031356)后 IE11无法打开使用解决办法

原因: 官方更新的最新系统补丁已经永久禁用IE11了 以下是官方说明: 最好的办法是: (已验证可行~) 1, 禁用系统自动更新 (注册表 或者 设置->更新->高级选项 等等 自行禁用掉系统自动更新即可) 2, 卸载禁用IE的更新补丁KB5031356 控制面板>程序>程序和功能>…

深入理解main函数

深入理解main函数 第三个参数指向环境变量

基于人工兔优化的BP神经网络(分类应用) - 附代码

基于人工兔优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码 文章目录 基于人工兔优化的BP神经网络&#xff08;分类应用&#xff09; - 附代码1.鸢尾花iris数据介绍2.数据集整理3.人工兔优化BP神经网络3.1 BP神经网络参数设置3.2 人工兔算法应用 4.测试结果&#x…

Qt第六十六章:展示数据的标签

目录 一、效果图 二、qtDesigner ①拖出一个frame作为组容器并贴上背景样式 ②拖出主要的三个控件&#xff1a;frame、line、frame、label*2 ③固定大小并设置字体、布局一下 ④拷贝三份并水平布局一下 ⑤设置样式 ⑥调整布局 三、ui文件 四、代码 一、效果图 二、qtD…

java蓝桥杯前10题总结

文章目录 1.单词分析1.代码2.知识点 2.成绩统计1.代码2.知识点1.如何四舍五入&#xff1f;2.如何保留小数点后几位小数呢&#xff1f; 3.最短路4.回文日期1.代码2.知识点1.日期类2.字符串细节3.连等的细节 5.门牌制作1.代码 6.卡片1.代码2.细节 7.数字三角形1.代码2.细节 8.成绩…

《向量数据库》——向量数据库MIlvus Cloud携手发起 AGI 黑客松,解锁行业更多可能

携手发起 AGI 黑客松,解锁行业更多可能 不止如此,双方在深度合作的基础上,还联合极客公园 Founder Park、智谱 AI 等,共同发起 AGI Playground Hackathon,旨在重新思考 AI Native 时代下的应用和服务,解决共同的行业发展问题。届时,Dify 将为参赛者提供接入了智谱 AI 模…

Domino中的源代码管理工具

大家好&#xff0c;才是真的好。 上次Notes/Domino 14 Drop2发布的时候&#xff0c;我们就提到&#xff0c;HCL一起发布了一款源代码管理工具。 这里还是简单科普一下&#xff0c;源代码管理工具&#xff0c;可以实现代码版本控制、备份&#xff0c;还有多个程序员之间的协作…

【ROOTFS】1-构建rootfs与nfs调试

简介 rootfs这一块比较简单&#xff0c;别怕&#xff0c;基本就是拿一个busybox过来&#xff0c;然后编译一下&#xff0c;就可以在指定的目录下生成一堆文件夹和文件&#xff0c;你可以把这个当成rootfs了&#xff1b; busybox: https://busybox.net/ 教程文档 【链接】 b…

绿盾控制台如何给未授权终端分配相应权限

环境&#xff1a; 绿盾控制台7.0 问题描述&#xff1a; 绿盾控制台如何给未授权终端分配相应权限 解决方案&#xff1a; 1.进入桌面管理系统 2.通过终端号&#xff0c;找到未授权终端下面&#xff0c;选择相应的未授权终端 3.点击鼠标右键&#xff0c;选择分配授权模块 4.下…

进阶课2——语音分类

语音分类主要是对语音从不同的维度进行识别和分类&#xff0c;这些维度可以包括语种、性别、年龄段、情绪、说话人身份等&#xff0c;具体如下&#xff1a; 语种分类&#xff1a;根据发音人的母语或者惯用语言&#xff0c;将语音分为不同的语种&#xff0c;例如中文、英文、法…

【UnityUGUI】UGUI六大组件和三大基本控件详解

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;元宇宙-秩沅 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 秩沅 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a;UI_…

用ChatGPT编写Excel函数公式进行表格数据处理分析,so easy!

在用Excel进行数据处理分析时&#xff0c;经常需要编写不同的公式&#xff0c;需要了解大量的函数。有了ChatGPT&#xff0c;就很简单了&#xff0c;直接用自然语言描述自己的需求&#xff0c;然后让ChatGPT写出公式就好了。 例子1&#xff1a; Excel某个单元格的内容是&#…

【鸿蒙软件开发】ArkTS常见组件之单选框Radio和切换按钮Toggle

文章目录 前言一、Radio单选框1.1 创建单选框1.2 添加Radio事件1.3 场景示例二、切换按钮Toggle2.1 创建切换按钮2.2 创建有子组件的Toggle2.3 自定义样式selectedColor属性switchPointColor属性 2.4 添加事件2.5 示例代码 总结 前言 Radio是单选框组件&#xff0c;通常用于提…

【深入探究Java集合框架】从List到Map的完整指南

文章目录 &#x1f31f; Java集合框架&#x1f34a; Collection&#x1f389; List&#x1f389; Set&#x1f389; Map &#x1f34a; 集合的选择&#x1f389; 1. 有序并允许重复元素的集合 List&#x1f389; 2. 无序并且不允许重复元素的集合 Set&#x1f389; 3. 维护映射…

大语言模型(LLM)综述(一):大语言模型介绍

A Survey of Large Language Models 前言1. INTRODUCTION2. OVERVIEW2.1 大语言模型的背景2.2 GPT系列模型的技术演变 前言 随着人工智能和机器学习领域的迅速发展&#xff0c;语言模型已经从简单的词袋模型&#xff08;Bag-of-Words&#xff09;和N-gram模型演变为更为复杂和…

DVWA(一)

环境搭建 搭建DVWA Web渗透测试靶场_dvwa 白屏-CSDN博客 Brute Force&#xff08;暴力破解&#xff09; LOW 输入账号密码 burp suite拦截请求 请求发送至intruder attack type:选择cluster bomb,将用户名和密码Add添加 payload 1 添加用户名字典&#xff0c;payload 2 添…

网工实验手册:RSTP如何配置?

1. 实验目的 熟悉RSTP的应用场景掌握RSTP的配置方法 想要华为数通配套实验拓扑和配置笔记的朋友们点赞关注&#xff0c;评论区留下邮箱发给你! 2. 实验拓扑 实验拓扑如图所示&#xff1a; 图&#xff1a;RSTP的配置 3. 实验步骤 &#xff08;1&#xff09; …

计算机网络——计算机网络体系结构(3/4)-计算机网络体系结构分层思想举例

目录 发送请求报文 应用层构建HTTP请求报文 运输层添加TCP首部 网络层添加IP首部 数据链路层形成帧 物理层转化为比特流 路由器处理 服务器处理 发回响应报文 计算机网络体系结构分层思想举例 假设网络拓扑如下所示&#xff0c;主机属于网络N1&#xff0c;Web服务器属…

卫星结构。。。

• 下图介绍了现代卫星中常见的组件&#xff0c;它们被分为 卫星有效载荷 和 卫星总线 。 – 卫星有效载荷 包括任务专用设备&#xff0c;例如用于地球观测的高分辨率相机或用于电信的强大无线电硬件。 – 卫星总线 包括操作和维护卫星所需的所有组件。 • 它被设计为独立于有效…

CorelDRAW Graphics Suite2024完整版最新功能介绍

CorelDRAW平面设计软件通常也被叫做CDR&#xff0c;CDR广泛应用于排版印刷、矢量图形编辑及网页设计等领域。通过CorelDRAW体验极具个性的自由创作&#xff0c;大胆展现真我&#xff0c;交付出众的创意作品。CorelDRAW拥有矢量插图、页面布局、图片编辑和设计工具&#xff0c;无…