【数据结构与算法】线索化二叉树

news2024/11/12 5:57:25

线索化二叉树

  1. n 个节点的二叉链表中含有 n + 1 【公式 2n - (n - 1) = n + 1】个空指针域。利用二叉链表中的空指针域,存放指向该节点在某种遍历次序下的前驱和后继节点的指针(这种附加的指针称为“线索”)。
  2. 这种加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Threaded BinaryTree)。根据线索性质不同,线索二叉树可分为前序线索二叉树、中序线索二叉树和后序线索二叉树三种。
  • 一个节点的前一个节点,称为前驱节点
  • 一个节点的后一个节点,称为后继节点

应用案例

中序遍历结果:{8,3,10,1,14,6}

在这里插入图片描述

说明:当线索化二叉树后,Node节点的属性 left 和 right,有如下情况

  1. left 指向的是左子树,也可能是指向的前驱节点,比如 1 节点的 left 指向左子树,而 10 节点的 left 指向的就是前驱节点。
  2. right 指向的是右子树,也可能指向的是后继节点,比如 1 节点 right 指向的是右子树,而 10 节点的 right 指向的是后继节点。

中序方式实现代码:

public class ThreadedBinaryTreeDemo {
    public static void main(String[] args) {
        // 测试
        HeroNode root = new HeroNode(1, "tom");
        HeroNode node2 = new HeroNode(3, "jack");
        HeroNode node3 = new HeroNode(6, "smith");
        HeroNode node4 = new HeroNode(8, "mary");
        HeroNode node5 = new HeroNode(10, "king");
        HeroNode node6 = new HeroNode(14, "dim");

        // 手动创建二叉树
        root.setLeft(node2);
        root.setRight(node3);
        node2.setLeft(node4);
        node2.setRight(node5);
        node3.setLeft(node6);

        // 测试中序线索化
        ThreadedBinaryTree threadedBinaryTree = new ThreadedBinaryTree();
        threadedBinaryTree.setRoot(root);
        threadedBinaryTree.threadedNodes();

        HeroNode leftNode = node5.getLeft();
        System.out.println(leftNode);
        HeroNode rightNode = node5.getRight();
        System.out.println(rightNode);
    }
}

// 定义 ThreadedBinaryTree 实现了线索化功能的二叉树
class ThreadedBinaryTree {
    private HeroNode root;
    // 为了实现线索化,需要创建一个指向当前节点的前驱节点的指针
    // 在递归进行线索化时,pre 总是保留前一个节点
    private HeroNode pre = null;

    public void setRoot(HeroNode root) {
        this.root = root;
    }

    public void threadedNodes() {
        this.threadedNodes(root);
    }

    /**
     * 对二叉树进行中序线索化
     *
     * @param node 就是当前需要线索化的节点
     */
    public void threadedNodes(HeroNode node) {
        // 如果 node == null,不能被线索化
        if (node == null) {
            return;
        }

        // (一)、先线索化左子树
        threadedNodes(node.getLeft());
        // (二)、线索化当前节点

        // 处理当前节点的前驱节点
        if (node.getLeft() == null) {
            // 让当前节点的左指针指向前驱节点
            node.setLeft(pre);
            // 修改当前节点的左指针类型,指向前驱节点
            node.setLeftType(1);
        }
        // 处理当前节点的后继节点
        if (pre != null && pre.getRight() == null) {
            // 让前驱节点的右指针指向当前节点
            pre.setRight(node);
            // 修改前驱节点的右指针类型
            pre.setLeftType(1);
        }

        // !!!每处理一个节点后,让当前节点是下一个节点的前驱节点
        pre = node;

        // (三)、再线索化右子树
        threadedNodes(node.getRight());
    }
}

// 创建 HeroNode 节点
class HeroNode {
    private int no;
    private String name;
    private HeroNode left;
    private HeroNode right;

    // 说明:
    // 1. 如果 leftType == 0 表示指向的是左子树,如果 1 表示指向的是前驱节点
    // 2. 如果 rightType == 0 表示指向的是右子树,如果 1 表示指向的是后继节点
    private int leftType;
    private int rightType;

    public HeroNode(int no, String name) {
        this.no = no;
        this.name = name;
    }

    public int getLeftType() {
        return leftType;
    }

    public void setLeftType(int leftType) {
        this.leftType = leftType;
    }

    public int getRightType() {
        return rightType;
    }

    public void setRightType(int rightType) {
        this.rightType = rightType;
    }

    public int getNo() {
        return no;
    }

    public void setNo(int no) {
        this.no = no;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public HeroNode getLeft() {
        return left;
    }

    public void setLeft(HeroNode left) {
        this.left = left;
    }

    public HeroNode getRight() {
        return right;
    }

    public void setRight(HeroNode right) {
        this.right = right;
    }

    @Override
    public String toString() {
        return "HeroNode{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }
}

遍历线索化二叉树

先进行二叉树的线索化,然后再进行遍历。

遍历演示:

    /**
     * 遍历线索化二叉树
     */
    public void threadedList() {
        // 定义一个变量,存储当前遍历的节点,从 root 开始
        HeroNode node = root;
        while (node != null) {
            // 虚幻的找到 leftType == 1 的节点,第一个找到的就是 8 节点
            // 后面随着遍历而变化,因为当 leftType == 1 时,说明节点是按照线索化处理后的有效节点
            while (node.getLeftType() == 0) {
                node = node.getLeft();
            }

            // 打印当前节点
            System.out.println(node);
            // 如果当前节点的右指针指向的是后继节点,就一直输出
            while (node.getRightType() == 1) {
                node = node.getRight();
                System.out.println(node);
            }

            // 替换这个遍历的节点
            node = node.getRight();
        }
    }

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

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

相关文章

Anteater/食蚁兽 V1.0.0 (帮助开发者快速找到项目中敏感信息)

Github>https://github.com/MartinxMax/Anteater 首页 Anteater/食蚁兽 V1.0.0 帮助开发者快速找到项目中存在敏感信息的文件,并且以时间戳为文件名保存日志 Anteater/食蚁兽 使用方法 #python3 anteater.py -h ps:当前目录下存在Windows_install.bat,Linux_install.sh请…

爆肝整理,Postman接口测试-参数关联实战(详细步骤)

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 接口测试什么时候…

忘掉MacType吧,TtfAutoHint手工删除ttc、ttf字体的hinting,微软雅黑字体更显平滑

Windows的ClearType渲染字体方式,结合臭名昭著的hinting技术使微软雅黑字体备受争议,正所谓:成也hinting,败也hinting。 首先什么是hinting? Hinting 这个词一直都没有中文名称,我用粤语将它音译为“牵挺”…

javascript 7种继承-- class继承(7)

文章目录 概要继承的进化史class继承1. 类声明与严格模式2. 类的实现3. 类的静态方法4. get,set 存取器5. 类中的公有继承以及私有继承6. 使用 super 调用超类7. Mix-ins / 混入 源码: 类的继承效果图小结 概要 这阵子在整理JS的7种继承方式,发现很多文…

【2023 华数杯全国大学生数学建模竞赛】 B题 不透明制品最优配色方案设计 详细建模方案解析及参考文献

【2023 华数杯全国大学生数学建模竞赛】 B题 不透明制品最优配色方案设计 详细建模方案解析及参考文献 1 题目 B 题 不透明制品最优配色方案设计 日常生活中五彩缤纷的不透明有色制品是由着色剂染色而成。因此,不透明制品的配色对其外观美观度和市场竞争力起着重要…

GD32F103VE定时器0

本测试程序,配置GD32F103VE定时器0每500ms中断一次,中断时,开关LED灯。 只讲定时器,多了,有点乱。有的人喜欢汇总,Timer的功能太多,放在一起,会搞混,不好移植。即使放一…

【雕爷学编程】MicroPython动手做(31)——物联网之Easy IoT 2

1、物联网的诞生 美国计算机巨头微软(Microsoft)创办人、世界首富比尔盖茨,在1995年出版的《未来之路》一书中,提及“物物互联”。1998年麻省理工学院提出,当时被称作EPC系统的物联网构想。2005年11月,国际电信联盟发布《ITU互联网…

哪些情况下需要使用爬虫IP

不知道小伙伴们有没有遇到过这种场景:上网闲逛,看一些搞笑的视频或者想下载一些酷炫的文件,正点击呢,结果却发现被网站限制了,无法访问或者下载? 别急,今天我来告诉大家,如何借助使…

IE浏览器,和Edge浏览器

目录 一.IE浏览器(前世今生) 1.什么是IE浏览器? 2.IE浏览器发展历程 3.IE浏览器在早些年为什么这么流行 4.ie浏览器为什么被停用? 5.IE浏览器无法适应如今的Web发展原因 二.Edge(发展) 1.什么是Edge浏览器&…

2023年人工智能技术与智慧城市发展白皮书

人工智能与智慧城市是当前热门的话题和概念,通过将人工智能技术应用在城市管理和服务中,利用自动化、智能化和数据化的方式提高城市运行效率和人民生活质量,最终实现城市发展的智慧化,提升城市居民的幸福感。 AI技术在城市中的应…

【修正-高斯拉普拉斯滤波器-用于平滑和去噪】基于修正高斯滤波拉普拉斯地震到达时间自动检测研究(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

iMX6ULL应用移植 | 移植 infoNES 模拟器(重玩经典NES游戏)

没玩过NES游戏的童年,可能不是80后的童年。我们小时候是从玩FC开始接触游戏机的,那时真的是红极一时啊,我上初中时还省吃俭用买了一台小霸王,暑假里把电视机都给打爆了!那时任天堂单是FC机的主机的发售收入就超过全美的…

小白解密ChatGPT大模型训练;Meta开源生成式AI工具AudioCraft

🦉 AI新闻 🚀 Meta开源生成式AI工具AudioCraft,帮助用户创作音乐和音频 摘要:美国公司Meta开源了一款名为AudioCraft的生成式AI工具,可以通过文本提示生成音乐和音频。该工具包含三个核心组件:MusicGen用…

Spring源码面试题

Spring源码面试题 谈谈你对Spring框架的理解? Spring 是一个开源的应用程序框架,它起源于 Rod Johnson 在其著名的 Spring Framework 专著中提出的一个轻量级框架的观念。下面是 Spring 的发展历史: 2002 年,Rod Johnson 发表了他的专著 …

GPT Prompt编写的艺术:如何提高AI模型的表现力

随着AI技术的迅速发展,人工智能模型变得越来越强大,能够协助我们完成各种任务。然而,如何更好地利用AI的能力仍然存在很大的探索空间。在与AI进行交互的过程中,我们主要依赖于Prompt,不管是直接与大模型交互&#xff0…

dlib的安装

由于需要人脸识别,所以需要安装opencv和dlib,OpenCV的安装很顺利,实例也跑的很正常。但dlib的安装却出现了很多坑,而且国内的解决方法都是复制粘贴,一点营养都没有,查了国外资料,终于解决&#…

让Python点亮你的世界:打造专业级编程环境的必备步骤

文章目录 初识pythonpython的安装win系统Linux系统(centos7) 第一个Python程序常见问题 Python解释器Python开发环境PyCharm的基础使用创建项目修改主题修改默认字体和大小汉化插件翻译软件常用快捷键 初识python Python语言的起源可以追溯到1989年&…

OFCMS代码审计

环境搭建 https://blog.csdn.net/oufua/article/details/82584637 安装后是重启容器 最后 db-config.properties 改成db.properties 修改数据库连接 搭建成功 代码审计 sql注入审计 全局搜索${ 查看没有预编译的sql语句,从而找到sql注入功能点 Ctrlalth 查看函…

AIGC大模型ChatGLM2-6B:国产版chatgpt本地部署及体验

1 ChatGLM2-6B介绍 ChatGLM是清华技术成果转化的公司智谱AI研发的支持中英双语的对话机器人。ChatGLM基于GLM130B千亿基础模型训练,它具备多领域知识、代码能力、常识推理及运用能力;支持与用户通过自然语言对话进行交互,处理多种自然语言任务…

干翻Dubbo系列第八篇:Dubbo直连开发核心三要素概述

文章目录 文章说明 一:Dubbo直连开发概念 1:直连设计中的核心组件 (一):Provider服务的提供者 (二): Consumer服务的访问者 (三):网络通信明白图 文章说明 本文内容整理自《孙哥说Dubbo系列视频课程》,孙帅老师…