线索化二叉树

简介: 线索化二叉树

线索化二叉树



前言:


对于线索化二叉树来说,他的后序线索化二叉树的遍历是其最难的地方,需要很多的辅助节点

对于中序、前序线索化二叉树相对来说比较简单。


Node节点类的代码:

public class Node {
    public int id;
    public String name;
    public Node right;
    public Node left;
    /**
     * l 作用 :标注left节点,若有值则为 0 无值,但经过序列化复制后为 1
     * r 作用 :标注right节点,若有值则为 0 无值,但经过序列化复制后为 1
     */
    public int l;
    public int r;
    public Node parent;  //用于后序序列化遍历时使用
    //前序遍历
    public void prefix(){
        System.out.println(this);
        if(this.left != null){
            this.left.prefix();
        }
        if (this.right != null){
            this.right.prefix();
        }
    }
    //中序遍历
    public void infix(){
        if(this.left != null){
            this.left.infix();
        }
        System.out.println(this);
        if (this.right != null){
            this.right.infix();
        }
    }
    //后序遍历
    public void suffix(){
        if(this.left != null){
            this.left.suffix();
        }
        if (this.right != null){
            this.right.suffix();
        }
        System.out.println(this);
    }
    public Node(int id, String name) {
        this.id = id;
        this.name = name;
    }
    @Override
    public String toString() {
        return "Node{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", left节点是否为空=" + l +
                ", right节点是否为空=" + r +
                '}';  //0为有值 / 1为线索化后有值
    }
}


前序线索化二叉树


思路:

线索化思路


首先判断当前节点是否为空,如果不为空再做处理。


  1. 左移至最左边,判定left为空时将临时节点指向当前node节点的左指针
  2. 处理右节点时是在下一次,此时node为下一个节点,而temp则指向上一轮的node节点。然后将temp指向的right节点连接到node(也就是当前节点)
  3. temp节点,让其始终跟在node节点的后面(node节点递归移动)
  4. 向左右分别递归移动当前节点


线索化遍历思路

根左右,所以从根节点开始,沿着左子树进行处理,当子节点的left指针类型是null时,给其left赋值,然后标注为此node的l= 1 说明到了最左子节点,然后处理子节点的right指针指向的节点,可能是右子树,也可能是后继节点,无论是哪种类型继续按照上面的方式(先沿着左子树处理,找到子树的最左子节点,然后处理right指针指向),以此类推,直到节点的right指针为空,说明是最后一个,遍历完成。


前序线索化

/**
 * 前序线索化
 */
public void prefixSearch(Node node){
    if (node == null){
        return;
    }
    //先处理左节点
    if(node.left == null){
        node.left = temp;
        node.l = 1;
    }
    //然后再处理右节点
    if(temp != null && temp.right == null){
        temp.right = node;
        temp.r = 1;
    }
    temp = node;
    //向左递归
    if(node.l == 0){
        prefixSearch(node.left);
    }
    //向右递归
    if(node.r == 0){
        prefixSearch(node.right);
    }
}


前序线索化的遍历

/**
 * 前序线索化二叉树的遍历
 */
public void prefixLink(){
    Node node = root;
    while(node != null){
        System.out.println(node);
        while(node.l == 0){
            node = node.left;
            System.out.println(node);
        }
        while(node.r == 1){
            node = node.right;
            System.out.println(node);
        }
        node = node.right;
    }
}


中序线索化二叉树


思路:

线索化思路


首先判断当前节点是否为空,如果不为空再做处理。


  1. 向左递归移动当前节点
  2. 判定left为空时将临时节点指向当前node节点的左指针
  3. 处理右节点时是在下一次,此时node为下一个节点,而temp则指向上一轮的node节点。然后将temp指向的right节点连接到node(也就是当前节点)
  4. temp节点,让其始终跟在node节点的后面(node节点递归移动)
  5. 向右递归移动当前节点


遍历思路

左根右,因此第一个节点一定是最左子节点,先找到最左子节点,依次沿着right指针指向进行处理(无论是指向子节点还是指向后继节点),直到节点的right指针为空,说明是最后一个,遍历完成。


中序线索化

/**
 * 使用中序线索化将节点连接
 * @param node : 为当前节点
 *        temp : 为当前节点的后面的节点
 */
public void infixSearch(Node node){
//首先,如果当前节点为空,那么就不用继续连接
    if(node == null){
        return;
    }
    //左递归找到最left的节点
    infixSearch(node.left);
    //来处理当前节点
    if (node.left == null){
        node.left = temp;   //如果当前节点的left为空,那么就说明已经递归到最left的节点了
        node.l = 1;         //标注,当前节点为叶子节点
    }
    //后面的节点不能为空 。 因为他必须遍历到最left边(最左边的叶子节点)才能开始使用temp节点
    if (temp!= null && temp.right == null){
        temp.right = node;
        temp.r = 1;
    }
    //移动辅助节点
    temp = node;
    //右递归找到最right的节点
    infixSearch(node.right);
}


中序线索化的遍历

/**
 * 中序线索化遍历
 */
public void infixLink(){
    //首先创建一个临时节点,用于遍历所有的节点
    Node node = root;
    while(node != null){
        //先循环到最left
        while(node.l == 0){
            node = node.left;
        }
        System.out.println(node);
        //然后判断,继续循环其他的
        while(node.r == 1){
            node = node.right;
            System.out.println(node);
        }
        node = node.right;
    }
}


后序线索化二叉树


思路:


线索化思路

首先判断当前节点是否为空,如果不为空再做处理。


  1. 向左递归移动当前节点
  2. 向右递归移动当前节点
  3. 判定left为空时将临时节点指向当前node节点的左指针
  4. 处理右节点时是在下一次,此时node为下一个节点,而temp则指向上一轮的node节点。然后将temp指向的right节点连接到node(也就是当前节点)
  5. temp节点,让其始终跟在node节点的后面(node节点递归移动)


线索化遍历思路


后序遍历线索化二叉树最为复杂,通用的二叉树数节点存储结构不能够满足后序线索化,因此我们扩展了节点的数据结构,增加了父节点的指针。后序的遍历顺序是:左右根,先找到最左子节点,沿着right后继指针处理,当right不是后继指针时,并且上一个处理节点是当前节点的右节点,则处理当前节点的右子树,遍历终止条件是:当前节点是root节点,并且上一个处理的节点是root的right节点。


后序线索化

/**
 * 后序线索化
 */
public void suffixSearch(Node node){
    if (node == null){
        return;
    }
    //向左递归
    suffixSearch(node.left);
    //向右递归
    suffixSearch(node.right);
    //先处理左节点
    if(node.left == null){
        node.left = temp;
        node.l = 1;
    }
    //然后再处理右节点
    if(temp != null && temp.right == null){
        temp.right = node;
        temp.r = 1;
    }
    temp = node;
}


后序线索化遍历★★★★★

/**
 * 后序线索化遍历★★★★★
 * 与前面的有所不用,终止为临时节点到root节点
 */
public void suffixLink(){
    Node node = root; //辅助指针1
    //先循环走到最左边
    while(node.l == 0){
        node = node.left;
    }
    Node pre = null;  //辅助指针2
    while(node != null){
        //如果节点被序列化,那么就右移,同时移动辅助指针2
        if (node.r == 1){
            System.out.println(node);
            pre = node;
            node = node.right;
        }else{
            //如果当前node节点有右节点,那么
            if(node.right == pre){
                System.out.println(node);
                if(node == root){
                    return;
                }
                pre = node;
                node = node.parent; // 回到父节点
            }else{
                node = node.right;
                while (node != null && node.l == 0){
                    node = node.left;
                }
            }
        }
    }
}
目录
相关文章
|
存储 缓存 Oracle
可能是最漂亮的Java I/O流详解
大家有什么思路吗?评论区一起讨论讨论。我需要使用 Java 逐行读取大约 5-6 GB 的大型文本文件。我怎样才能快速完成此操作?最高赞的回答是叫Peter Lawrey的老哥回答的。大家好,我是南哥。一个Java学习与进阶的领路人,今天指南的是Java I/O流,跟着南哥我们一起在Java之路上成长。本文收录在我开源的《Java学习进阶指南》中,涵盖了想要学习Java、成为更好的Java选手都在偷偷看的核心知识、面试重点。
207 1
可能是最漂亮的Java I/O流详解
|
运维 Cloud Native 关系型数据库
活动回顾丨首期阿里云 Serverless 技术创新实战营上海开讲(含 PPT 下载)
活动回顾丨首期阿里云 Serverless 技术创新实战营上海开讲(含 PPT 下载)
|
弹性计算 固态存储 大数据
阿里云服务器1核2G/2核4G/4核8G/8核16配置ECS实例规格汇总
阿里云ECS云服务器1核2G、2核4G、2核8G、4核8G、4核16G、8核16、8核32G云服务器配置可选ECS实例规格汇总,汇总阿里云服务器各个配置可选的ECS实例规格:
《高考前夕时间旅行的可行性研究报告》
熵并不能阻止时光倒流。                  ——鲁迅   如果我能回到过去,我一定要把彩票号码带给自己; 如果我能回到过去,我一定会督促自己在夏天之前减肥; 如果我能回到过去,我一定……还会选择和TA相遇…… 很可惜,我们也就只能想一想而已。
1214 0
|
17天前
|
存储 弹性计算 人工智能
【2025云栖精华内容】 打造持续领先,全球覆盖的澎湃算力底座——通用计算产品发布与行业实践专场回顾
2025年9月24日,阿里云弹性计算团队多位产品、技术专家及服务器团队技术专家共同在【2025云栖大会】现场带来了《通用计算产品发布与行业实践》的专场论坛,本论坛聚焦弹性计算多款通用算力产品发布。同时,ECS云服务器安全能力、资源售卖模式、计算AI助手等用户体验关键环节也宣布升级,让用云更简单、更智能。海尔三翼鸟云服务负责人刘建锋先生作为特邀嘉宾,莅临现场分享了关于阿里云ECS g9i推动AIoT平台的场景落地实践。
【2025云栖精华内容】 打造持续领先,全球覆盖的澎湃算力底座——通用计算产品发布与行业实践专场回顾
|
9天前
|
云安全 人工智能 安全
Dify平台集成阿里云AI安全护栏,构建AI Runtime安全防线
阿里云 AI 安全护栏加入Dify平台,打造可信赖的 AI
|
12天前
|
人工智能 运维 Java
Spring AI Alibaba Admin 开源!以数据为中心的 Agent 开发平台
Spring AI Alibaba Admin 正式发布!一站式实现 Prompt 管理、动态热更新、评测集构建、自动化评估与全链路可观测,助力企业高效构建可信赖的 AI Agent 应用。开源共建,现已上线!
1045 33
|
11天前
|
机器学习/深度学习 人工智能 搜索推荐
万字长文深度解析最新Deep Research技术:前沿架构、核心技术与未来展望
近期发生了什么自 2025 年 2 月 OpenAI 正式发布Deep Research以来,深度研究/深度搜索(Deep Research / Deep Search)正在成为信息检索与知识工作的全新范式:系统以多步推理驱动大规模联网检索、跨源证据。
806 55
下一篇
开通oss服务