第八话 树结构的基本知识

8. 树结构的基本知识

8.1 为什么需要树这种数据结构

  1. 数组存储方式的分析:

    优点:通过小标方式访问元素,速度快,对于有序数组,还可以使用二分查找提高检索速度。

    缺点:如果要检索具体某个值,或者插入值(按照一定顺序)会整体移动,效率低

  2. 链式存储方式的分析

    优点:在一定程度上对数组存储方式有优化(比如:插入一个数值节点,只需要将插入节点,连接到链表中即可,删除效率也很高)。

    缺点:在进行检索的时候,效率仍然很低,比如(检索某个值,需要从头节点开始遍历)

  3. 树存储方式的分析

    能提高数据存储,读取的效率,比如利用二叉排序树(Binary Sort Tree),既可以保证数据的检索速度,同时也可以保证数据的插入,删除,修改的速度。

分析二叉排序树

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CIHXNwSM-1618541752657)(C:\Users\dongwei\AppData\Roaming\Typora\typora-user-images\image-20210401125952349.png)]

8.2 二叉树的概念和常用术语

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G9leczkW-1618541752661)(C:\Users\dongwei\AppData\Roaming\Typora\typora-user-images\image-20210401130700479.png)]

二叉树的概念

  1. 树有很多种,每个节点最多只能有两个子节点的一种形式叫做二叉树。
  2. 二叉树的子节点分为左节点和右节点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3OBX2DJH-1618541752664)(C:\Users\dongwei\AppData\Roaming\Typora\typora-user-images\image-20210401131815539.png)]

  1. 如果该二叉树的所有叶子节点都在最后一层,并且节点总数是2^-1,n为层数,则我们称为满二叉树。
  2. 如果该二叉树的所有叶子节点都在最后一层或者倒数第二层,而且最后一层的叶子节点在左边连续,倒数第二层的叶子节点在右边连续,我们称为完全二叉树。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FVCjCaCf-1618541752668)(C:\Users\dongwei\AppData\Roaming\Typora\typora-user-images\image-20210401143621262.png)]

8.3 二叉树的遍历说明

前序遍历:**先输出父节点,**再遍历左子树和右子树

中序遍历:先遍历左子树,**再输出父节点,**最后遍历右子树

后序遍历:先遍历左子树,再遍历右子树,最后输出父节点

小结:

看输出父节点的顺序,就确定是前序,中序还是后序。

二叉树分析

  1. 创建一个二叉树

  2. 前序遍历

    2.1 先输出当前节点(初始的时候是root节点)

    2.2 如果左节点不为空则递归继续前序遍历

    2.3 如果右节点不为空则递归继续前序遍历

  3. 中序遍历

    3.1 如果当前节点的左子节点不为空,则递归中序遍历

    3.2 输出当前节点

    3.3 如果当前节点的右子节点不为空,则递归中序遍历

  4. 后序遍历

    4.1 如果当前节点的左子节点不为空,则递归后序遍历

    4.2 如果当前节点的右子节点不为空,则递归后序遍历

    4.3 输出当前节点

8.4 二叉树代码实现

8.4.1 前序中序后序的代码实现

public class BinaryTreeDemo {
    public static void main(String[] args) {
        //先创建一个二叉树
        BinaryTree binaryTree = new BinaryTree();
        //需要创建的节点
        HeroNode root = new HeroNode(1,"松江");
        HeroNode node2 = new HeroNode(2,"松江");
        HeroNode node3 = new HeroNode(3,"松江");
        HeroNode node4 = new HeroNode(4,"松江");
        //说明,我们先手动创建该二叉树,后面学习递归的方式创建二叉树
        root.setLeft(node2);
        root.setRight(node3);
        node3.setRight(node4);
        binaryTree.setRoot(root);

        //测试
        System.out.println("前序遍历");
        binaryTree.preOrder();

        System.out.println("中序遍历");
        binaryTree.infixOrde();

        System.out.println("后序遍历");
        binaryTree.postOrder();

    }
}
//定义一个二叉树
class BinaryTree{
    private HeroNode root;
    public void setRoot(HeroNode root){
        this.root = root;
    }
    //前序遍历
    public void preOrder(){
        if (this.root != null){
            this.root.preOrder();
        } else {
            System.out.println("二叉树为空无法遍历");
        }
    }
    //中序遍历
    public void infixOrde(){
        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("二叉树为空,无法遍历");
        }
    }
}

//先创建HeroNode节点
class HeroNode{
    private int no;
    private String name;
    private HeroNode left;  //默认为null
    private HeroNode right; //默认为null
    public HeroNode(int no,String name){
        this.no = no;
        this.name = name;
    }
    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;
    }
    public String toString(){
        return "HeroNode [no="+no+",name="+name+"]";
    }

    //编写前序遍历的方法
    public void preOrder(){
        System.out.println(this); //先输出父节点
        //递归向左子树前序遍历
        if (this.left != null){
            this.left.preOrder();
        }
        //递归向右子树遍历
        if (this.right != null){
            this.right.preOrder();
        }
    }
    //中序遍历
    public void infixOrder(){
        //递归向左子树中序遍历
        if (this.left != null){
            this.left.infixOrder();
        }
        //输出父节点
        System.out.println(this);
        //递归右子树中序遍历
        if (this.right != null){
            this.right.infixOrder();
        }
    }
    //后序遍历
    public void postOrder(){
        if (this.left != null){
            this.left.postOrder();
        }
        if (this.right != null){
            this.right.postOrder();
        }
        System.out.println(this);
    }
}

结果实现

前序遍历
HeroNode [no=1,name=松江]
HeroNode [no=2,name=松江]
HeroNode [no=3,name=松江]
HeroNode [no=4,name=松江]
中序遍历
HeroNode [no=2,name=松江]
HeroNode [no=1,name=松江]
HeroNode [no=3,name=松江]
HeroNode [no=4,name=松江]
后序遍历
HeroNode [no=2,name=松江]
HeroNode [no=4,name=松江]
HeroNode [no=3,name=松江]
HeroNode [no=1,name=松江]

8.4.2 查找指定的节点

要求

  1. 请编写前序查找,中序查找和后序查找的方法
  2. 并分别使用三种查找方式,查找HeroNO = 5的节点
  3. 并分析各种查找方式,分别比较了多少次

思路分析

前序查找思路

  1. 先判断当前节点的no是否等于要查找的
  2. 如果相等返回当前节点
  3. 如果不相等,则判断当前节点的左子节点是否为空,如果不为空则递归前序查找
  4. 如果左递归前序查找,找到节点,则返回,否则继续查找,当前的节点的右子节点是否为空,如果不为空的话则继续由递归前序查找

中序查找思路

  1. 判断当前节点的左子节点是否为空 ,如果不为空则递归中序查找
  2. 如果找到则返回,如果没有找到的话,就和当前节点比较,如果是则返回当前节点,否则的话继续进行由递归中序查找
  3. 如果右递归中序查找,找到的话就返回,否则的话返回null

后序查找思路

  1. 判断当前节点的左子节点是否为空,如果不为空,则递归后序查找
  2. 如果找到,就返回,如果没有找到就判断当前节点的右子节点是否为空,如果不为空,则右递归进行后序查找,如果找到就返回。
  3. 就和当前节点进行比较,如果是则返回,否则的话直接返回null。
public class BinaryTreeDemo {
    public static void main(String[] args) {
        //先创建一个二叉树
        BinaryTree binaryTree = new BinaryTree();
        //需要创建的节点
        HeroNode root = new HeroNode(1,"松江");
        HeroNode node2 = new HeroNode(2,"松江");
        HeroNode node3 = new HeroNode(3,"松江");
        HeroNode node4 = new HeroNode(4,"松江");
        HeroNode node5 = new HeroNode(5,"松江");
        //说明,我们先手动创建该二叉树,后面学习递归的方式创建二叉树
        root.setLeft(node2);
        root.setRight(node3);
        node3.setRight(node4);
        node3.setLeft(node5);
        binaryTree.setRoot(root);

        //测试
        System.out.println("前序遍历");
        binaryTree.preOrder();

        System.out.println("中序遍历");
        binaryTree.infixOrde();

        System.out.println("后序遍历");
        binaryTree.postOrder();

        //搜索遍历查找
//        System.out.println("前序遍历方式~~~~~");
//        HeroNode resNode = binaryTree.preOrderSearch(5);
//        if (resNode != null){
//            System.out.printf("已经找到了,no=%d,name=%s",resNode.getNo(),resNode.getName());
//        } else {
//            System.out.println("没有查找到相关信息");
//        }

//        System.out.println("中序遍历方式~~~~~");
//        HeroNode resNode = binaryTree.infixOrderSearch(5);
//        if (resNode != null){
//            System.out.printf("已经找到了,no=%d,name=%s",resNode.getNo(),resNode.getName());
//        } else {
//            System.out.println("没有查找到相关信息");
//        }

        System.out.println("后序遍历方式~~~~~");
        HeroNode resNode = binaryTree.postOrderSearch(5);
        if (resNode != null){
            System.out.printf("已经找到了,no=%d,name=%s",resNode.getNo(),resNode.getName());
        } else {
            System.out.println("没有查找到相关信息");
        }
    }
}
//定义一个二叉树
class BinaryTree{
    private HeroNode root;
    public void setRoot(HeroNode root){
        this.root = root;
    }
    //前序遍历
    public void preOrder(){
        if (this.root != null){
            this.root.preOrder();
        } else {
            System.out.println("二叉树为空无法遍历");
        }
    }
    //中序遍历
    public void infixOrde(){
        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 root.postOrderSearch(no);
        } else {
            return null;
        }
    }
}

//先创建HeroNode节点
class HeroNode{
    private int no;
    private String name;
    private HeroNode left;  //默认为null
    private HeroNode right; //默认为null
    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;
    }
    public String toString(){
        return "HeroNode [no="+no+",name="+name+"]";
    }

    //编写前序遍历的方法
    public void preOrder(){
        System.out.println(this); //先输出父节点
        //递归向左子树前序遍历
        if (this.left != null){
            this.left.preOrder();
        }
        //递归向右子树遍历
        if (this.right != null){
            this.right.preOrder();
        }
    }
    //中序遍历
    public void infixOrder(){
        //递归向左子树中序遍历
        if (this.left != null){
            this.left.infixOrder();
        }
        //输出父节点
        System.out.println(this);
        //递归右子树中序遍历
        if (this.right != null){
            this.right.infixOrder();
        }
    }
    //后序遍历
    public void postOrder(){
        if (this.left != null){
            this.left.postOrder();
        }
        if (this.right != null){
            this.right.postOrder();
        }
        System.out.println(this);
    }
    //前序遍历查找
    public HeroNode preOrderSearch(int no){
        System.out.println("进入前序遍历::::");
        //比较当前节点是不是
        if (this.no == no){
            return this;
        }
        //1. 判断当前节点的左子节点是否为空,如果不为空就递归前序查找
        //2. 如果左递归前序查找,找到节点,则返回
        HeroNode resNode = null;
        if (this.left != null){
            resNode = this.left.preOrderSearch(no);
        }
        if (resNode != null){
            //说明左子树找到了
            return resNode;
        }
        //1. 左递归前序查找,找到节点,则返回,否则继续判断
        //2. 当前系欸但的右子节点是否为空,如果不为空,则继续向右递归前序查找
        if (this.right != null){
            resNode = this.right.preOrderSearch(no);
        }
        return resNode;//不管有没有都要返回了,如果没有的话返回的是null。
    }

    //中序遍历查找
    public HeroNode infixOrderSearch(int no){

        HeroNode resNode = null;
        if (this.left != null){
            resNode = this.left.infixOrderSearch(no);
        }
        if (resNode != null){
            return resNode;
        }
        //如果找到就直接返回,如果没有找到,就和当前节点比较,如果是就返回当前节点
        System.out.println("进入中序遍历::::");
        if (this.no == no){
            return this;
        }
        if (this.right != null){
            resNode = this.right.infixOrderSearch(no);
        }
        return resNode;
    }

     //后遍历查找
    public HeroNode postOrderSearch(int no){
        HeroNode resNode = null;
        if (this.left != null){
            resNode = this.left.postOrderSearch(no);
        }
        if (resNode != null){
            return resNode;
        }
        if (this.right != null){
            resNode = this.right.postOrderSearch(no);
        }
        if (resNode != null){
            return resNode;
        }
        System.out.println("进入后序遍历::::");
        if (this.no == no){
            return this;
        }
        return resNode;
    }
}

结果

前序遍历
HeroNode [no=1,name=松江]
HeroNode [no=2,name=松江]
HeroNode [no=3,name=松江]
HeroNode [no=5,name=松江]
HeroNode [no=4,name=松江]
中序遍历
HeroNode [no=2,name=松江]
HeroNode [no=1,name=松江]
HeroNode [no=5,name=松江]
HeroNode [no=3,name=松江]
HeroNode [no=4,name=松江]
后序遍历
HeroNode [no=2,name=松江]
HeroNode [no=5,name=松江]
HeroNode [no=4,name=松江]
HeroNode [no=3,name=松江]
HeroNode [no=1,name=松江]
后序遍历方式~~~~~
进入后序遍历::::
进入后序遍历::::
已经找到了,no=5,name=松江

8.4.3 二叉树删除节点

要求:

  1. 如果删除的节点是叶子节点,则删除该节点
  2. 如果删除的节点是非叶子节点,则删除该子树
  3. 测试,删除掉5号叶子节点和3号子树

思路:

  1. 因为我们的二叉树是单向的,所以我们是判断当前节点的子节点是否是需要删除的节点,而不能去判断当前这个节点是不是需要删除节点
  2. 如果当前节点的左子节点不为空,并且左子节点就是要删除节点,就将this.left = null;并且返回(结束递归删除)。
  3. 如果当前节点的右子节点不为空,并且右子节点就是要删除节点,就将this.right = null;并且就返回(结束递归删除)。
  4. 如果第2步和第3步没有删除节点,那么我们就需要向左子树进行递归删除,
  5. 如果第4步也没有删除节点,则应当向右子树进行递归删除。
  6. 考虑如果树是空树root,如果只有一个root节点,则等价将二叉树置空。

在HeroNode中编写删除的代码

    //递归删除节点
    //1. 如果删除的是叶子节点,则删除该节点
    //2. 如果删除的节点是非叶子节点,则删除该子树
    public void delNode(int no){
        //如果当前节点的左子节点不为空,并且左子节点就是要删除的点
        if (this.left != null && this.left.no == no){
            this.left = null;
            return;
        }
        //如果当前节点的右子节点不为空,并且右子节点就是要删除的点
        if (this.right != null && this.right.no == no){
            this.right = null;
            return;
        }
        //如果上面都没有要删除的节点
        if (this.left != null){
            this.left.delNode(no);
        }
        if (this.right != null){
            this.right.delNode(no);
        }
    }

我觉得this很关键

在binaryTree里面编写删除方法

    //删除节点
    public void delNode(int no){
        if (root != null){
            if (root.getNo() == no){
                root = null;
            } else {
                root.delNode(no);
            }
        } else {
            System.out.println("这个二叉树是个空树");
        }
    }

运行结果

删除前,前序遍历~~~
HeroNode [no=1,name=松江]
HeroNode [no=2,name=松江]
HeroNode [no=3,name=松江]
HeroNode [no=5,name=松江]
HeroNode [no=4,name=松江]
删除后,前序遍历~~~
HeroNode [no=1,name=松江]
HeroNode [no=2,name=松江]

8.4.4 顺序存储二叉树

基本说明

从数据存储来看,数据存储方式和树的存储方式可以相互转换,树也可以转换成数组,

要求:

  1. 二叉树的节点,可以以数组的方式来存放 arr:[1,2,3,4,5,6,7]
  2. 要求在遍历数组arr的时候,仍然可以以前序遍历,中序遍历和后序遍历的方式完成节点的遍历

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xSn5aBHW-1618541752673)(C:\Users\dongwei\AppData\Roaming\Typora\typora-user-images\image-20210403101535883.png)]

顺序存储二叉树的特点

  1. 顺序二叉树通常只考虑完全二叉树
  2. 第n个元素的左子节点为 2*n+1
  3. 第n个元素的右子节点为2*n+2
  4. 第n个元素的父节点为(n-1)/2
  5. n:表示二叉树的第几个元素(按0开始编号)

要求:给一个数组[1,2,3,4,5,6,7],要求以二叉树前遍历的方式进行遍历,前遍历的结果应当为1,2,4,5,3,6,7

8.5 线索化二叉树

问题分析

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4JKhKtuN-1618541752675)(C:\Users\dongwei\AppData\Roaming\Typora\typora-user-images\image-20210403151152295.png)]

  1. 当我们对上面的二叉树进行中序遍历时,数列为{8,3,10,1,6,14}
  2. 但是6,8,10,14这几个节点的左右指针,并没有完全利用上
  3. 如果我们希望充分的利用各个节点的左右指针,让各个节点可以指向自己的前后节点怎么办?
  4. 可以使用线索二叉树来实现

线索二叉树的基本介绍

  1. n个节点的二叉链表中含有n+1个空指针域。利用二叉链表中的空指针域,存放指向该节点在某种遍历次序下的前驱和后继节点的指针(这种附加的指针称为“线索”
  2. 这种加上线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树(Thread Binary Tree)。根据线索性质的不同,线索二叉树可以分为前序线索二叉树,中序线索二叉树和后序线索二叉树三种
  3. 一个节点的前一个节点,称为前驱节点
  4. 一个节点的后一个节点,称为后继节点

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-69Hliss6-1618541752676)(C:\Users\dongwei\AppData\Roaming\Typora\typora-user-images\image-20210403154712100.png)]

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

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

8.5.1 线索二叉树的代码

代码实现

//定义ThreadedBinaryTree 实现了线索化功能的二叉树
class ThreadedBinaryTree {
    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();

        // 测试: 以10号节点测试
        HeroNode leftNode = node5.getLeft();
        HeroNode rightNode = node5.getRight();
        System.out.println("10号结点的前驱结点是 =" + leftNode); // 3
        System.out.println("10号结点的后继结点是=" + rightNode); // 1

    }


    private HeroNode root;

    // 为了实现线索化,需要创建一个指向当前结点的前驱结点的指针
    // 在递归进行线索化时,pre 总是保留前一个结点
    private HeroNode pre = null;

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

    // 重载一把threadedNodes方法
    public void threadedNodes() {
        this.threadedNodes(root);
    }

    // 编写对二叉树进行中序线索化的方法
    // node 就是当前需要线索化的结点
    public void threadedNodes(HeroNode node) {

        // 如果node==null, 不能线索化
        if (node == null) {
            return;
        }

        // (一)先线索化左子树
        threadedNodes(node.getLeft());

        // (二)线索化当前结点[有难度]
        // 处理当前结点的前驱结点
        // 以8结点来理解
        // 8结点的.left = null , 8结点的.leftType = 1
        if (node.getLeft() == null) {
            // 让当前结点的左指针指向前驱结点
            node.setLeft(pre);
            // 修改当前结点的左指针的类型,指向前驱结点
            node.setLeftType(1);
        }

        // 处理后继结点
        if (pre != null && pre.getRight() == null) {
            // 让前驱结点的右指针指向当前结点
            pre.setRight(node);
            // 修改前驱结点的右指针类型
            pre.setRightType(1);
        }
        // !!! 每处理一个结点后,让当前结点是下一个结点的前驱结点
        pre = node;

        // (三)在线索化右子树
        threadedNodes(node.getRight());

    }
}


//先创建HeroNode 结点
class HeroNode {
    private int no;
    private String name;
    private HeroNode left; // 默认null
    private HeroNode right; // 默认null
    // 说明
    // 1. 如果leftType == 0 表示指向的是左子树, 如果 1 则表示指向前驱结点
    // 2. 如果rightType == 0 表示指向是右子树, 如果 1表示指向后继结点
    private int leftType;
    private int rightType;

    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 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 + "]";
    }

}

结果

10号结点的前驱结点是 =HeroNode [no=3, name=jack]
10号结点的后继结点是=HeroNode [no=1, name=tom]

8.5.2 遍历线索二叉树

**说明:**对前面的中序线索化的二叉树,进行遍历

**分析:**因为线索化后,各个节点指向有变化,因此原来的遍历方式是不可以使用的,这个时候需要使用新的方式遍历线索化二叉树,各个节点可以通过线索型方式遍历,因此无需使用递归方式,这样也提高了遍历的效率,遍历的次序应当和中序保持一致。

  //遍历线索化二叉树的方法
    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();
        }
    }

结果

使用线索化的方法遍历线索化二叉树~~~~~
HeroNode [no=8, name=mary]
HeroNode [no=3, name=jack]
HeroNode [no=10, name=king]
HeroNode [no=1, name=tom]
HeroNode [no=14, name=dim]
HeroNode [no=6, name=smith]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值