高龄白菜java学习第九十四、五天(java数据结构和算法(14))

四、顺序存储二叉树

代码实现

package Tree.BinaryTree;

//顺序存储二叉树
public class ArrBinaryTree {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5, 6, 7};
        ArrTree tree = new ArrTree(arr);
        tree.preOrder();
        System.out.println();
        tree.infixOrder();
        System.out.println();
        tree.postOrder();
        System.out.println();
    }
}

//编写一个ArrBinaryTree,实现顺序存储二叉树遍历
class ArrTree {
    private int[] arr;

    public ArrTree(int[] arr) {
        this.arr = arr;
    }

    //重载后外部无需再输入参数下标
    public void preOrder() {
        this.preOrder(0);
    }

    public void infixOrder() {
        this.infixOrder(0);
    }

    public void postOrder() {
        this.postOrder(0);
    }

    //前序遍历
    public void preOrder(int index) {//数组下标
        if (arr == null || arr.length == 0) {
            System.out.println("数组为空,无法遍历");
            return;
        }
        System.out.print(arr[index] + "   ");
        //向左遍历递归
        if (index * 2 + 1 < arr.length) {
            preOrder(index * 2 + 1);
        }
        if (index * 2 + 2 < arr.length) {
            preOrder(index * 2 + 2);
        }
    }

    //中序遍历
    public void infixOrder(int index) {//数组下标
        if (arr == null || arr.length == 0) {
            System.out.println("数组为空,无法遍历");
            return;
        }
        if (index * 2 + 1 < arr.length) {
            infixOrder(index * 2 + 1);
        }
        System.out.print(arr[index] + "   ");
        if (index * 2 + 2 < arr.length) {
            infixOrder(index * 2 + 2);
        }
    }

    //后序遍历
    public void postOrder(int index) {//数组下标
        if (arr == null || arr.length == 0) {
            System.out.println("数组为空,无法遍历");
            return;
        }
        if (index * 2 + 1 < arr.length) {
            postOrder(index * 2 + 1);
        }
        if (index * 2 + 2 < arr.length) {
            postOrder(index * 2 + 2);
        }
        System.out.print(arr[index] + "   ");
    }
}

五、线索化二叉树

注:
1、n个节点共有2n个指针,除去根节点的其他n-1个节点,会占用对应父节点的一个指针,因此,空指针的数量等于二者相减
2、节点=》该节点

数组中打头的没有前驱节点,末尾的没有后继节点
说明中的情况要在代码中体现

六、遍历线索化二叉树

思路分析
1、先取到要遍历的第一个节点(第一个lefttType=1但left=0的节点)
2、如果后驱节点一直存在,就一直输出,直到遇到right域指向的是右子树的节点时(即rightType=0时),将当前临时节点node替换为此节点
3、继续通过新的node节点执行上述的操作,直到right指向为空
​ 解释:因为实现线索化二叉树中是通过下个节点的pre来设置后驱节点,而最后一个节点无下个节点,不会被设置后驱,rightTpye=0所以走外层while:通过右子树是否为空这个条件,作为判断是否实现全部二叉树的线索化遍历的依据

重要提示:在中序线索化中,是在回溯的过程中进行节点的pre域进行操作,因此递归不需要对pre指向的是前驱节点还是左子树进行判断;而在前序线索化中,是先进行了节点操作后进行递归,因此在递归时有必要判断,即递归的条件是leftType=0

代码实现

package Tree.ThreadedBinaryTree;

public class ThreadedBinaryTree {
    public static void main(String[] args) {
        HeroNode root = new HeroNode(1, "1");
        HeroNode n2 = new HeroNode(3, "3");
        HeroNode n3 = new HeroNode(6, "6");
        HeroNode n4 = new HeroNode(8, "8");
        HeroNode n5 = new HeroNode(10, "10");
        HeroNode n6 = new HeroNode(14, "14");

        root.left = n2;
        root.right = n3;
        n2.left = n4;
        n2.right = n5;
        n3.left = n6;
        ThreadTree tree = new ThreadTree();
        tree.setRoot(root);

//        tree.threadedInfixNodes();
        //找一个点做验证,10的前后是否是3和1
//        System.out.println(n6.left);
//        System.out.println(n6.right);
//        tree.threadedInfixList();
        System.out.println("===============");

//        tree.threadedPreNodes();
//        System.out.println(n4.left);
//        System.out.println(n4.right);
//        tree.threadedPreList();

        tree.threadedPostNodes();
//        System.out.println(n4.left);
//        System.out.println(n4.right);
        tree.threadedPostList();
    }
}

//定义一个树
class ThreadTree {
    private HeroNode root;

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

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

    //重载
    public void threadedInfixNodes() {
        this.threadedInfixNodes(root);
    }

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

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

    //二叉树前序线索化
    public void threadedPreNodes(HeroNode node) {
        if (node == null) {
            return;
        }
        //左指针为空时,指向前驱节点
        if (node.left == null) {
            node.left = pre;
            node.leftType = 1;
        }
        //后继节点是在下一次处理的(在下一个节点中,用pre表示上一个节点然后进行设置)
        //最后一个节点没有下一个节点,自然也就没有了后继节点
        if (pre != null && pre.right == null) {
            pre.right = node;
            pre.rightType = 1;
        }
        pre = node;
        //处理左子树
        if (node.leftType == 0) {
            threadedPreNodes(node.left);
        }
        //处理右子树
        if (node.rightType == 0) {
            threadedPreNodes(node.right);
        }
    }

    //二叉树中序线索化
    public void threadedInfixNodes(HeroNode node) {//需要线索化的节点
        if (node == null) {
            return;
        }
        ;
        //先线索化左子树、再当前节点、再右子树
        threadedInfixNodes(node.left);
        //线索化当前节点
        if (node.left == null) {//前驱节点使用pre
            node.left = pre;
            node.leftType = 1;
        }
        //后继节点是在下一次处理的(在下一个节点中,用pre表示上一个节点然后进行设置)
        //最后一个节点没有下一个节点,自然也就没有了后继节点
        if (pre != null && pre.right == null) {
            pre.right = node;
            pre.rightType = 1;
        }
        pre = node;

        threadedInfixNodes(node.right);

    }

    //二叉树后序线索化
    public void threadedPostNodes(HeroNode node) {
        if (node == null) {
            return;
        }

        //处理左子树
        if (node.leftType == 0) {
            threadedPostNodes(node.left);
        }
        //处理右子树
        if (node.rightType == 0) {
            threadedPostNodes(node.right);
        }

        //左指针为空时,指向前驱节点
        if (node.left == null) {
            node.left = pre;
            node.leftType = 1;
        }
        //后继节点是在下一次处理的(在下一个节点中,用pre表示上一个节点然后进行设置)
        //最后一个节点没有下一个节点,自然也就没有了后继节点
        if (pre != null && pre.right == null) {
            pre.right = node;
            pre.rightType = 1;
        }
        pre = node;
    }

    //线索化前序遍历
    public void threadedPreList() {
        HeroNode node = root;
        while (node != null) {
            //循环的找到leftType=1的节点
            while (node.leftType == 0) {//第一个leftType=1的节点就是首节点
                System.out.println(node);
                node = node.left;
            }
            //打印当前这个节点
            System.out.println(node);
            node = node.right;
        }
    }

    //线索化中序遍历
    public void threadedInfixList() {
        //定义一个临时变量,存储当前遍历的节点,从root开始
        HeroNode node = root;
        while (node != null) {
            //循环的找到leftType=1的节点
            while (node.leftType == 0) {//第一个leftType=1的节点就是首节点
                node = node.left;
            }
            //打印当前这个节点
            System.out.println(node);
            //如果当前节点的右指针指向的是后继节点,就一直输出
            while (node.rightType == 1) {
                node = node.right;
                System.out.println(node);
            }
            //while结束时,说明遇到了右指针指向的是右子树的节点,
            // 此时把这个节点替换为node,重复进行新一轮的while操作
            node = node.right;
        }
    }

    //线索化后序遍历
    public void threadedPostList() {
        //定义一个临时变量,存储当前遍历的节点,从root开始
        HeroNode node = root;

        //找后序遍历开始的节点
        HeroNode pre = null;
        while (node != null && node.leftType == 0) {
            node = node.left;
        }

        while (node!=null){
            if (node.rightType==1){
                System.out.println(node);
                pre=node;
                node=node.right;
            } else {
                //如果上个处理的节点是当前节点的右节点
                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.leftType==0){
                        node=node.left;
                    }
                }
            }
        }
    }

    //前序遍历
    public void preOrder() {
        if (root != null) {
            this.root.preOrder();
        } else {
            System.out.println("当前二叉树为空,无法遍历");
        }
    }

    //中序遍历
    public void infixOrder() {
        if (root != null) {
            this.root.infixOrder();
        } else {
            System.out.println("当前二叉树为空,无法遍历");
        }
    }

    //后序遍历
    public void postOrder() {
        if (root != null) {
            this.root.postOrder();
        } else {
            System.out.println("当前二叉树为空,无法遍历");
        }
    }

    //前序查找
    public HeroNode preOrderSearch(int no) {
        if (root != null) {
            HeroNode res = this.root.preOrderSearch(no);
            if (res.no == no) {
                return res;
            }
            return null;
        } else {
            return null;
        }
    }

    //中序查找
    public HeroNode infixOrderSearch(int no) {
        if (root != null) {
            HeroNode res = this.root.infixOrderSearch(no);
            if (res.no == no) {
                return res;
            }
            return null;
        } else {
            return null;
        }
    }

    //后序查找
    public HeroNode postOrderSearch(int no) {
        if (root != null) {
            HeroNode res = this.root.postOrderSearch(no);
            if (res.no == no) {
                return res;
            }
            return null;
        } else {
            return null;
        }
    }

    //删除
    public void del(int no) {
        if (root != null) {
            if (root.no == no) {
                root = null;
            } else {
                this.root.del(no);
            }
        } else {
            System.out.println("二叉树为空,无法继续删除");
        }
    }
}

//先创建HeroNode节点
class HeroNode {
    public int no;
    public String name;
    public HeroNode left;
    public HeroNode right;
    public int leftType;//等于0代表是左子树,等于1代表是前驱节点
    public int rightType;
    public HeroNode parent;

    public HeroNode() {
    }

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

    @Override
    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) {
        //先判断父节点
        if (this.no == no) {
            return this;
        } else {
            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;//为空说明都没找到,不为空说明在右子树找到,最后的判断放在上层做
        }
    }

    //中序查找
    public HeroNode infixOrderSearch(int no) {
        HeroNode resNode = null;
        if (this.left != null) {//递归前序查找
            resNode = this.left.infixOrderSearch(no);
        }
        if (resNode != null) {//说明左子树找到
            return resNode;
        }
        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;
        }
        return this;
    }

    //删除
    public void del(int no) {
        if (this.left != null && this.left.no == no) {
            if (this.left.left != null) {
                this.left = this.left.left;
            } else if (this.left.right != null) {
                this.left = this.left.right;
            } else {
                this.left = null;
            }
            return;
        }
        if (this.right != null && this.right.no == no) {
            if (this.right.left != null) {
                this.right = this.right.left;
            } else if (this.right.right != null) {
                this.right = this.right.right;
            } else {
                this.right = null;
            }
            return;
        }
        if (this.left != null) {
            this.left.del(no);
        }
        if (this.right != null) {
            this.right.del(no);
        }
    }
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值