数据结构与算法__07--前序、中序、后序线索化二叉树,前序、中序、后序线索化二叉树遍历(Java语言版本)

简介: 前序、中序、后序线索化二叉树,前序、中序、后序线索化二叉树遍历汇总(Java语言版本)

@[toc]

1 前序

//前序线索化二叉树
public void threadedPreNode(HeroNode node) {
    if (node == null) {
        return;
    }
    //线索化当前节点
    if (node.getLeft() == null) {
        node.setLeft(pre);
        node.setLeftType(1);
    }
    if (pre != null && pre.getRight() == null) {
        pre.setRight(node);
        pre.setRightType(1);
    }
    pre = node;
    //线索化左子树
    if (node.getLeftType() != 1) {
        threadedPreNode(node.getLeft());
    }
    //线索化右子树
    if (node.getRightType() != 1) {
        threadedPreNode(node.getRight());
    }
 
}
 
//前序线索化遍历
public void threadedPreList() {
    //定义一个变量,存储当前遍历的结点,从root开始
    HeroNode node = root;
    while (node != null) {
        //打印当前这个结点
        System.out.println(node);
        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();
 
    }
}

2 后序

2.1 为节点添加父节点

2.1.1 节点中创建方法

//前序遍历添加父节点
public void preOrderAddPar() {
    while (this.getLeft() != null) {
        this.getLeft().setParent(this);
        break;
    }
    while (this.getRight() != null) {
        this.getRight().setParent(this);
        break;
    }
 
    if (this.getLeft() != null) {//2.向左遍历
        this.getLeft().preOrderAddPar();
    }
    if (this.getRight() != null) {//3.向右遍历
        this.getRight().preOrderAddPar();
    }
}

2.1.2 二叉树中创建方法

//前序遍历添加父节点
public void preOrderAddPar() {
    if (this.root != null) {
        this.root.preOrderAddPar();
    } else {
        System.out.println("二叉树为空");
    }
}

2.2 后序线索化及遍历

//后序线索化二叉树   8,10,3,14,6,1
public void threadedPostNode(HeroNode node) {
    if (node == null) {
        return;
    }
    //线索化左子树
    threadedPostNode(node.getLeft());
 
    //线索化右子树
    threadedPostNode(node.getRight());
    //线索化当前节点
    if (node.getLeft() == null) {
        node.setLeft(pre);
        node.setLeftType(1);
    }
    if (pre != null && pre.getRight() == null) {
        pre.setRight(node);
        pre.setRightType(1);
    }
    pre = node;
}
 
//后序遍历线索化二叉树的方法
public void threadedPostList() {//8,10,3,14,6,1
    HeroNode node = root;
    while(node != null && node.getLeftType()!=1) {
        node = node.getLeft();
    }
 
    HeroNode pre = null;
    while(node != null) {
        //右节点是线索
        if (node.getRightType() == 1) {
            System.out.println(node);
            pre = node;
            node = node.getRight();
 
        } else {
            //如果上个处理的节点是当前节点的右节点
            if (node.getRight() == pre) {
                System.out.println(node);
                if (node == root) {
                    return;
                }
 
                pre = node;
                node = node.getParent();
 
            } else {    //如果从左节点的进入则找到有子树的最左节点
                node = node.getRight();
                while (node != null && node.getLeftType() !=1) {
                    node = node.getLeft();
                }
            }
        }
    }
}

3 中序

//重载中序线索化二叉树
public void threadedNode() {
    threadedNode(root);
}
 
//中序遍历线索化二叉树的方法
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();
 
    }
}
 
//中序线索化二叉树
public void threadedNode(HeroNode node) {
    if (node == null) {
        return;
    }
    //线索化左子树
    threadedNode(node.getLeft());
    //线索化当前节点
    if (node.getLeft() == null) {
        node.setLeft(pre);
        node.setLeftType(1);
    }
    if (pre != null && pre.getRight() == null) {
        pre.setRight(node);
        pre.setRightType(1);
    }
    pre = node;
    //线索化右子树
    threadedNode(node.getRight());
}

4 完整代码

package edu.seu.demo10tree.demothreadedbinarytree;
 
public class Demo01ThreadedBinaryTree {
    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.preOrderAddPar();
        
//        中序  8, 3, 10, 1, 14, 6
/*        threadedBinaryTree.threadedNode();
        HeroNode leftNode = node5.getLeft();
        HeroNode rightNode = node5.getRight();
        System.out.println("10号结点的前驱结点是="  + leftNode); //3
        System.out.println("10号结点的后继结点是="  + rightNode); //1
        System.out.println("使用线索化的方式遍历 线索化二叉树");
        threadedBinaryTree.threadedList();*/
 
//        前序 1,3,8,10,6,14
/*        threadedBinaryTree.threadedPreNode(root);
        HeroNode leftNode = node5.getLeft();
        HeroNode rightNode = node5.getRight();
        System.out.println("10号结点的前驱结点是=" + leftNode);
        System.out.println("10号结点的后继结点是=" + rightNode);
        System.out.println("使用线索化的方式遍历 线索化二叉树");
        threadedBinaryTree.threadedPreList();*/
 
        //后序8,10,3,14,6,1
        threadedBinaryTree.threadedPostNode(root);
        HeroNode leftNode = node5.getLeft();
        HeroNode rightNode = node5.getRight();
        System.out.println("10号结点的前驱结点是=" + leftNode);
        System.out.println("10号结点的后继结点是=" + rightNode);
 
        System.out.println("使用线索化的方式遍历 线索化二叉树");
        threadedBinaryTree.threadedPostList();
 
    }
}
 
class HeroNode {
    private int no;//英雄编号
    private String name;//姓名
    private HeroNode left;//左子节点
    private HeroNode right;//右子节点
    private HeroNode parent;//父节点
    private int rightType;//表示右子节点:指针:0,后继:1
    private int leftType;//表示左子节点:指针:0  前驱:1
 
    public HeroNode getParent() {
        return parent;
    }
 
    public void setParent(HeroNode parent) {
        this.parent = parent;
    }
 
    public int getRightType() {
        return rightType;
    }
 
    public void setRightType(int rightType) {
        this.rightType = rightType;
    }
 
    public int getLeftType() {
        return leftType;
    }
 
    public void setLeftType(int leftType) {
        this.leftType = leftType;
    }
 
    public HeroNode(int no, String name) {
        this.no = no;
        this.name = name;
    }
 
    //读取与设置私有变量
    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 preOrderAddPar() {
        while (this.getLeft() != null) {
            this.getLeft().setParent(this);
            break;
        }
        while (this.getRight() != null) {
            this.getRight().setParent(this);
            break;
        }
 
        if (this.getLeft() != null) {//2.向左遍历
            this.getLeft().preOrderAddPar();
        }
        if (this.getRight() != null) {//3.向右遍历
            this.getRight().preOrderAddPar();
        }
    }
 
    //前序遍历
    public void preOrder() {
        System.out.println(this);//1.输出父节点
        if (this.getLeft() != null) {//2.向左遍历
            this.getLeft().preOrder();
        }
        if (this.getRight() != null) {//3.向右遍历
            this.getRight().preOrder();
        }
    }
 
    //中序遍历
    public void infixOrder() {
        if (this.getLeft() != null) {
            this.getLeft().infixOrder();
        }
        System.out.println(this);
        if (this.getRight() != null) {//3.向右遍历
            this.getRight().infixOrder();
        }
    }
 
    //后序遍历
    public void postOrder() {
        if (this.getLeft() != null) {
            this.getLeft().postOrder();
        }
        if (this.getRight() != null) {//3.向右遍历
            this.getRight().postOrder();
        }
        System.out.println(this);
    }
 
    //前序遍历查找
    public HeroNode preOrderSearch(int no) {
        System.out.println("前序查找比较次数");
        if (this.getNo() == no) {
            return this;
        }
        HeroNode resHero = null;
        if (this.left != null) {
            resHero = this.left.preOrderSearch(no);
        }
        if (resHero != null) {
            return resHero;
        }
        if (this.right != null) {
            resHero = this.right.preOrderSearch(no);
        }
        return resHero;
    }
 
    //中序遍历查找
    public HeroNode infixOrderSearch(int no) {
        HeroNode resHero = null;
        if (this.left != null) {
            resHero = this.left.infixOrderSearch(no);
        }
        if (resHero != null) {
            return resHero;
        }
        System.out.println("中序查找比较次数");
        if (this.getNo() == no) {
            return this;
        }
        if (this.right != null) {
            resHero = this.right.infixOrderSearch(no);
        }
        return resHero;
    }
 
    //后序遍历查找
    public HeroNode postOrderSearch(int no) {
        HeroNode resHero = null;
        if (this.left != null) {
            resHero = this.left.postOrderSearch(no);
        }
        if (resHero != null) {
            return resHero;
        }
 
        if (this.right != null) {
            resHero = this.right.postOrderSearch(no);
        }
        if (resHero != null) {
            return resHero;
        }
        System.out.println("后序查找比较次数");
        if (this.getNo() == no) {
            return this;
        }
        return resHero;
    }
 
    //删除节点
    public void delHeroNode(int no) {
        if (this.left != null && this.left.getNo() == no) {
            this.left = null;
            return;
        }
        if (this.right != null && this.right.getNo() == no) {
            this.right = null;
            return;
        }
        if (this.left != null) {
            this.left.delHeroNode(no);
        }
        if (this.right != null) {
            this.right.delHeroNode(no);
        }
    }
 
}
 
class ThreadedBinaryTree {
    private HeroNode root;//根节点
    private HeroNode pre = null;
 
    public ThreadedBinaryTree() {
    }
 
    public HeroNode getRoot() {
        return root;
    }
 
    public void setRoot(HeroNode root) {
        this.root = root;
    }
 
    //重载中序线索化二叉树
    public void threadedNode() {
        threadedNode(root);
    }
 
    //中序遍历线索化二叉树的方法
    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();
 
        }
    }
 
    //中序线索化二叉树
    public void threadedNode(HeroNode node) {
        if (node == null) {
            return;
        }
        //线索化左子树
        threadedNode(node.getLeft());
        //线索化当前节点
        if (node.getLeft() == null) {
            node.setLeft(pre);
            node.setLeftType(1);
        }
        if (pre != null && pre.getRight() == null) {
            pre.setRight(node);
            pre.setRightType(1);
        }
        pre = node;
        //线索化右子树
        threadedNode(node.getRight());
    }
 
    //后序线索化二叉树   8,10,3,14,6,1
    public void threadedPostNode(HeroNode node) {
        if (node == null) {
            return;
        }
        //线索化左子树
        threadedPostNode(node.getLeft());
 
        //线索化右子树
        threadedPostNode(node.getRight());
        //线索化当前节点
        if (node.getLeft() == null) {
            node.setLeft(pre);
            node.setLeftType(1);
        }
        if (pre != null && pre.getRight() == null) {
            pre.setRight(node);
            pre.setRightType(1);
        }
        pre = node;
    }
 
    //后序遍历线索化二叉树的方法
    public void threadedPostList() {//8,10,3,14,6,1
        HeroNode node = root;
        while(node != null && node.getLeftType()!=1) {
            node = node.getLeft();
        }
 
        HeroNode preNode = null;
        while(node != null) {
            //右节点是线索
            if (node.getRightType() == 1) {
                System.out.println(node);
                preNode = node;
                node = node.getRight();
 
            } else {
                //如果上个处理的节点是当前节点的右节点
                if (node.getRight() == preNode) {
                    System.out.println(node);
                    if (node == root) {
                        return;
                    }
 
                    preNode = node;
                    node = node.getParent();
 
                } else {    //如果从左节点的进入则找到有子树的最左节点
                    node = node.getRight();
                    while (node != null && node.getLeftType() !=1) {
                        node = node.getLeft();
                    }
                }
            }
        }
    }
 
    //前序线索化二叉树
    public void threadedPreNode(HeroNode node) {
        if (node == null) {
            return;
        }
        //线索化当前节点
        if (node.getLeft() == null) {
            node.setLeft(pre);
            node.setLeftType(1);
        }
        if (pre != null && pre.getRight() == null) {
            pre.setRight(node);
            pre.setRightType(1);
        }
        pre = node;
        //线索化左子树
        if (node.getLeftType() != 1) {
            threadedPreNode(node.getLeft());
        }
        //线索化右子树
        if (node.getRightType() != 1) {
            threadedPreNode(node.getRight());
        }
 
    }
 
    //前序线索化遍历
    public void threadedPreList() {
        //定义一个变量,存储当前遍历的结点,从root开始
        HeroNode node = root;
        while (node != null) {
            //打印当前这个结点
            System.out.println(node);
            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();
 
        }
    }
 
    //前序遍历添加父节点
    public void preOrderAddPar() {
        if (this.root != null) {
            this.root.preOrderAddPar();
        } else {
            System.out.println("二叉树为空");
        }
    }
    //前序遍历
    public void preOrder() {
        if (this.root != null) {
            this.root.preOrder();
        } else {
            System.out.println("二叉树为空");
        }
    }
 
    //中序遍历
    public void infixOrder() {
        if (this.root != null) {
            this.root.infixOrder();
        } else {
            System.out.println("二叉树为空");
        }
    }
 
    //后序遍历
    public void postOrder() {
        if (this.root != null) {
            this.root.postOrder();
        } else {
            System.out.println("二叉树为空");
        }
    }
 
    //前序遍历查找
    public HeroNode preOrderSearch(int no) {
        if (root != null) {
            return root.preOrderSearch(no);
        } else {
            return null;
        }
    }
 
    //中序遍历查找
    public HeroNode infixOrderSearch(int no) {
        if (root != null) {
            return root.infixOrderSearch(no);
        } else {
            return null;
        }
    }
 
    //后序遍历查找
    public HeroNode postOrderSearch(int no) {
        if (root != null) {
            return this.root.postOrderSearch(no);
        } else {
            return null;
        }
    }
 
    //删除节点
    public void delHeroNode(int no) {
        if (root != null) {
            if (root.getNo() == no) {
                root = null;
            } else {
                root.delHeroNode(no);
            }
        } else {
            System.out.println("二叉树为空");
        }
    }
}
相关文章
|
9月前
|
负载均衡 算法 关系型数据库
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
本文聚焦 MySQL 集群架构中的负载均衡算法,阐述其重要性。详细介绍轮询、加权轮询、最少连接、加权最少连接、随机、源地址哈希等常用算法,分析各自优缺点及适用场景。并提供 Java 语言代码实现示例,助力直观理解。文章结构清晰,语言通俗易懂,对理解和应用负载均衡算法具有实用价值和参考价值。
大数据大厂之MySQL数据库课程设计:揭秘MySQL集群架构负载均衡核心算法:从理论到Java代码实战,让你的数据库性能飙升!
|
9月前
|
人工智能 算法 NoSQL
LRU算法的Java实现
LRU(Least Recently Used)算法用于淘汰最近最少使用的数据,常应用于内存管理策略中。在Redis中,通过`maxmemory-policy`配置实现不同淘汰策略,如`allkeys-lru`和`volatile-lru`等,采用采样方式近似LRU以优化性能。Java中可通过`LinkedHashMap`轻松实现LRUCache,利用其`accessOrder`特性和`removeEldestEntry`方法完成缓存淘汰逻辑,代码简洁高效。
371 0
|
10月前
|
前端开发 Java
java实现队列数据结构代码详解
本文详细解析了Java中队列数据结构的实现,包括队列的基本概念、应用场景及代码实现。队列是一种遵循“先进先出”原则的线性结构,支持在队尾插入和队头删除操作。文章介绍了顺序队列与链式队列,并重点分析了循环队列的实现方式以解决溢出问题。通过具体代码示例(如`enqueue`入队和`dequeue`出队),展示了队列的操作逻辑,帮助读者深入理解其工作机制。
345 1
|
11月前
|
存储 负载均衡 算法
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
309 15
|
4月前
|
存储 人工智能 算法
从零掌握贪心算法Java版:LeetCode 10题实战解析(上)
在算法世界里,有一种思想如同生活中的"见好就收"——每次做出当前看来最优的选择,寄希望于通过局部最优达成全局最优。这种思想就是贪心算法,它以其简洁高效的特点,成为解决最优问题的利器。今天我们就来系统学习贪心算法的核心思想,并通过10道LeetCode经典题目实战演练,带你掌握这种"步步为营"的解题思维。
|
11月前
|
监控 算法 安全
基于 PHP 语言深度优先搜索算法的局域网网络监控软件研究
在当下数字化时代,局域网作为企业与机构内部信息交互的核心载体,其稳定性与安全性备受关注。局域网网络监控软件随之兴起,成为保障网络正常运转的关键工具。此类软件的高效运行依托于多种数据结构与算法,本文将聚焦深度优先搜索(DFS)算法,探究其在局域网网络监控软件中的应用,并借助 PHP 语言代码示例予以详细阐释。
260 1
|
12月前
|
运维 监控 算法
监控局域网其他电脑:Go 语言迪杰斯特拉算法的高效应用
在信息化时代,监控局域网成为网络管理与安全防护的关键需求。本文探讨了迪杰斯特拉(Dijkstra)算法在监控局域网中的应用,通过计算最短路径优化数据传输和故障检测。文中提供了使用Go语言实现的代码例程,展示了如何高效地进行网络监控,确保局域网的稳定运行和数据安全。迪杰斯特拉算法能减少传输延迟和带宽消耗,及时发现并处理网络故障,适用于复杂网络环境下的管理和维护。
|
存储 算法 安全
探究‘公司禁用 U 盘’背后的哈希表算法与 Java 实现
在数字化办公时代,信息安全至关重要。许多公司采取“禁用U盘”策略,利用哈希表算法高效管理外接设备的接入权限。哈希表通过哈希函数将设备标识映射到数组索引,快速判断U盘是否授权。例如,公司预先将允许的U盘标识存入哈希表,新设备接入时迅速验证,未授权则禁止传输并报警。这有效防止恶意软件和数据泄露,保障企业信息安全。 代码示例展示了如何用Java实现简单的哈希表,模拟公司U盘管控场景。哈希表不仅用于设备管理,还在文件索引、用户权限等多方面助力信息安全防线的构建,为企业数字化进程保驾护航。
|
8月前
|
存储 安全 Java
Java 集合面试题从数据结构到 HashMap 源码剖析详解及长尾考点梳理
本文深入解析Java集合框架,涵盖基础概念、常见集合类型及HashMap的底层数据结构与源码实现。从Collection、Map到Iterator接口,逐一剖析其特性与应用场景。重点解读HashMap在JDK1.7与1.8中的数据结构演变,包括数组+链表+红黑树优化,以及put方法和扩容机制的实现细节。结合订单管理与用户权限管理等实际案例,展示集合框架的应用价值,助你全面掌握相关知识,轻松应对面试与开发需求。
400 3
|
11月前
|
存储 算法 安全
企业员工数据泄露防范策略:基于 C++ 语言的布隆过滤器算法剖析[如何防止员工泄密]
企业运营过程中,防范员工泄密是信息安全领域的核心议题。员工泄密可能致使企业核心数据、商业机密等关键资产的流失,进而给企业造成严重损失。为应对这一挑战,借助恰当的数据结构与算法成为强化信息防护的有效路径。本文专注于 C++ 语言中的布隆过滤器算法,深入探究其在防范员工泄密场景中的应用。
245 8