ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

线索化二叉树详解

2021-06-06 22:04:59  阅读:156  来源: 互联网

标签:return no HeroNode 线索 public 详解 二叉树 null 节点


线索化二叉树详解

说明

  1. 线索化二叉树,由字面意思,就是将二叉树的节点拿线索连接起来
  2. 实质上,也就是将二叉树的叶子节点左右指针域彼此连接一个节点
  3. 二叉树的非叶子节点的左右指针域都各自连接了一个节点,但是叶子节点的左右指针域是空的,因此考虑将叶子节点的左右指针域按照某种遍历次序连接起来
  4. 按照二叉树的遍历方式,有前序中序后续三种遍历方式,因此可以形成三种链式结构
  5. 每个叶子节点前一个节点称为前驱节点,后一个节点称为后继节点,如果当前节点没有前驱或者后继节点,则直接置为空
  6. 以中序线索化二叉树为例,编写中序线索化二叉树的方法
  7. 先判断当前节点是否为空,如果为空,则直接返回
  8. 否则先向左递归线索化二叉树的左子树
  9. 然后再线索化当前节点,定义属性pre保存当前节点的前一个节点,因此当前节点的前一个节点置为pre
  10. 注意当前节点的后一个节点,需要用pre保存当前节点,然后遍历到后一个节点,然后用pre指向
  11. 注意第一个节点和最后一个节点
  12. 中序线索化如下,前序和后续类似

源码及分析

节点类
//创建节点
class HeroNode{
    //编号
    private int no;
    //姓名
    private String name;
    //左子树
    private HeroNode left;
    //右子树
    private HeroNode right;

    //线索化的前驱节点类型,是节点还是树,假定 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 + '\'' +
                '}';
    }
    //删除节点

    /**
     *
     * @param no 要删除的节点编号
     */
    public void delNode(int no){
        //判断当前节点的左子树是否为空,如果不为空,再判断是否为要删除的节点
        if (this.left != null && this.left.no == no){
            this.left = null;
        }
        //判断当前节点的右子树是否为空,如果不为空,再判断是否为要删除的节点
        if (this.right != null && this.right.no == no){
            this.right = null;
        }
        //否则向左向右递归
        if (this.left != null){
            this.left.delNode(no);
        }
        if (this.right != null){
            this.right.delNode(no);
        }
    }


    //前序中序后序遍历主要区别在于父节点的输出位置不同,
    /**
     * 前序遍历先输出父节点信息,然后判断左子树是否为空,如果不为空,则递归前序遍历
     * 然后再判断右子树是否为空,如果不为空,则递归遍历前序遍历
     */
    //前序遍历
    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);
    }

    //前序查找

    /**
     * 前序遍历查找
     * @param no 要查找的节点编号
     * @return 返回查找的结果
     */
    public HeroNode preOrderSearch(int no){
        //先判断当前节点是不是要查找的节点
        if (this.no == no){
            return this;
        }
        //如果当前节点不是要查找的节点,则判断左子树是否为空,若不为空,则递归前序查找
        HeroNode resNode = null;
        if (this.left != null){
            resNode = this.left.preOrderSearch(no);
        }
        //如果在左子树找到,则直接返回
        if (resNode != null){
            return resNode;
        }
        //如果左子树也没有找到,则判断右子树是否为空,并递归
        if (this.right != null){
            resNode = this.right.preOrderSearch(no);
        }
        return resNode;
    }
    //中序查找

    /**
     * 中序遍历查找
     * @param no 要查找的节点编号
     * @return 返回查找的结果
     */
    public HeroNode infixOrderSearch(int no){
        //先判断当前节点左子树是否为空,如果不为空则递归中序查找
        //定义变量保存查找的结果
        HeroNode resNode = null;
        if (this.left != null){
            resNode = this.left.preOrderSearch(no);
        }
        //如果查找到,则直接返回
        if (resNode != null){
            return resNode;
        }
        //如果没有找到,判断当前节点是不是要查找的节点
        if (this.no == no){
            return this;
        }
        //如果还没有找到,则判断右子树是否为空,不为空则递归中序查找
        if (this.right != null){
            resNode = this.right.infixOrderSearch(no);
        }
        return resNode;
    }
    //后序查找

    /**
     * 后续遍历查找
     * @param no 要查找的节点编号
     * @return 返回查找的结果
     */
    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;
        }
        if (this.no == no){
            return this;
        }
        return resNode;
    }
}

线索化二叉树类
//创建一颗线索化二叉树
class ThreaderBinaryTree{
    //二叉树必有根节点
    private HeroNode root;
    //定义变量指向前驱节点,默认为空
    private HeroNode pre = null;

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

    //编写中序线索化二叉树的方法
    /**
     *
     * @param node node为当前要中序线索化的节点
     */
    public void infixThreadedBinaryTree(HeroNode node){
        //先判断当前节点是否为空
        if (node == null){
            return;
        }
        //如果不为空,先线索化左子树
        infixThreadedBinaryTree(node.getLeft());
        //再线索化当前节点
        //当前节点的前驱节点为pre,后继节点需要在下一个节点连通,因为是单向的

        //设置当前节点的前驱节点,并设置前驱节点类型
        if (node.getLeft() == null){
            node.setLeft(pre);
            node.setLeftType(1);
        }
        //设置当前节点的后继节点及其类型
        if (pre != null && pre.getRight() == null){
            pre.setRight(node);
            pre.setRightType(1);
        }
        //让pre指向当前节点
        pre = node;
        //最后再线索化右子树
        infixThreadedBinaryTree(node.getRight());
    }
    //重载线索化的方法
    public void infixThreadedBinaryTree(){
        this.infixThreadedBinaryTree(root);
    }

    //删除节点
    /**
     *
     * @param no 要删除的节点编号
     */
    public void delNode(int no){
        //先判断二叉树是否为空
        if (this.root != null){
            //再判断当前root节点是不是要删除的节点
            if (this.root.getNo() == no){
                root = null;
            }else {
                this.root.delNode(no);
            }
        }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 (this.root != null){
            return this.root.preOrderSearch(no);
        }else {
            return null;
        }
    }
    //中序查找
    public HeroNode infixOrderSearch(int no){
        if (this.root != null){
            return this.root.infixOrderSearch(no);
        }else {
            return null;
        }
    }
    //后续查找
    public HeroNode postOrderSearch(int no){
        if (this.root != null){
            return this.root.postOrderSearch(no);
        }else {
            return null;
        }
    }
}
测试类
public static void main(String[] args) {
        ThreaderBinaryTree threaderBinaryTree = new ThreaderBinaryTree();
        HeroNode root = new HeroNode(1,"tom");
        HeroNode node2 = new HeroNode(3,"jack");
        HeroNode node3 = new HeroNode(6,"smith");
        HeroNode node4 = new HeroNode(8,"king");
        HeroNode node5 = new HeroNode(10,"mary");
        HeroNode node6 = new HeroNode(14,"dop");
        root.setLeft(node2);
        root.setRight(node3);
        node2.setLeft(node4);
        node2.setRight(node5);
        node3.setLeft(node6);
        threaderBinaryTree.setRoot(root);

        //进行线索化
        threaderBinaryTree.infixThreadedBinaryTree();

        //测试线索化的结果
        System.out.println("node5的前一个节点 = " + node5.getLeft());
        System.out.println("node5的后一个节点 = " + node5.getRight());

    }

标签:return,no,HeroNode,线索,public,详解,二叉树,null,节点
来源: https://www.cnblogs.com/mx-info/p/14856527.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有