数据结构与算法(Java)之二叉树

二叉树

package com.weeks.tree;

/**
 * @author 达少
 * @version 1.0
 *
 * 实现二叉树数据结构
 */
public class BinaryTreeDemo {
    public static void main(String[] args) {
        //定义二叉树
        BinaryTree binaryTree = new BinaryTree();
        //定义二叉树的节点对象
        HeroNode node1 = new HeroNode(1, "宋江");
        HeroNode node2 = new HeroNode(2, "吴用");
        HeroNode node3 = new HeroNode(3, "卢俊义");
        HeroNode node4 = new HeroNode(4, "林冲");
        HeroNode node5 = new HeroNode(5, "关胜");
        //这里先使用手动创建二叉树,以后可以使用递归方式创建
        binaryTree.setRoot(node1);
        node1.setLeft(node2);
        node1.setRight(node3);
        node3.setRight(node4);
        node3.setLeft(node5);

        //测试前序遍历
//        System.out.println("前序遍历");
//        binaryTree.preOrder();//1,2,3,5,4

        //测试中序遍历
//        System.out.println("中序遍历");
//        binaryTree.infixOrder();//2,1,5,3,4

        //测试后续遍历
//        System.out.println("后续遍历");
//        binaryTree.postOrder();//2,5,4,3,1

        //测试前序查找
//        HeroNode resNode = binaryTree.preOrderSearch(5);
//        HeroNode resNode = binaryTree.infixOrderSearch(5);
//        HeroNode resNode = binaryTree.postOrderSearch(5);
//        if(resNode != null){
//            System.out.printf("找到了结点id = %d, name = %s\n", resNode.getNo(), resNode.getName());
//        }else{
//            System.out.println("没有找到要查找的结点!!!");
//        }

        System.out.println("删除前的二叉树(前序遍历)");
        binaryTree.preOrder();
        //删除no=5的结点
        binaryTree.delNode(5);
        System.out.println("删除后的二叉树(前序遍历)");
        binaryTree.preOrder();
    }
}

//定义二叉树类
class BinaryTree{
    private HeroNode root;//根结点

    public HeroNode getRoot() {
        return root;
    }

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

    //前序遍历
    public void preOrder(){
        if(root == null){
            return;
        }
        root.preOrder();
    }

    //中序遍历
    public void infixOrder(){
        if(root == null){
            return;
        }
        root.infixOrder();
    }

    //后序遍历
    public void postOrder(){
        if(root == null){
            return;
        }
        root.postOrder();
    }

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

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

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

    //删除结点
    public void delNode(int no){
        //判断二叉树是否为空
        if(root == null){
            return;
        }
        //判断根节点是否符合删除条件,符合则将整棵树置空后返回
        if(root.getNo() == no){
            root = null;
            return;
        }else{//否则执行HeroNode中的delNode操作
            root.delNode(no);
        }
    }
}

//定义树的结点对象类
class HeroNode{
    private int no;
    private String name;
    private HeroNode left;
    private HeroNode right;

    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 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 找到就返回该结点,否则返回null
     */
    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;//返回不为空就是找打了,返回空就是没有找到
    }

    //中序查找
    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(this.no == no){
            return this;
        }
        return resNode;
    }

    //删除结点
    /**
     * 约定:
     * 如果删除的是叶子结点,则直接删除
     * 如果不是也只结点直接删除以该节点为父节点的子树
     */
    public void delNode(int no){
        /**
         * 1.因为要现在创建的二叉树是单向的,要删除只能找到父节点分别判断左右结点是否符合
         *   删除的条件,所以首先判断左子树是否有符合删除的条件的结点,递归实现
         * 2.接下来是递归判断右子树中是否有符合删除条件的结点
         */
        //判断该节点是否有左子树并判断左子树是否符合删除条件
        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);
        }
    }
}

顺序存储二叉树

package com.weeks.tree;

import java.util.ArrayList;

/**
 * @author 达少
 * @version 1.0
 *
 * 顺序存储二叉树
 */
public class ArrayBinaryTreeDemo {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5, 6, 7};
        ArrayBinaryTree arrayBinaryTree = new ArrayBinaryTree(arr);
//        arrayBinaryTree.preOrder();
//        arrayBinaryTree.infixOrder();
        arrayBinaryTree.postOrder();
    }
}

//顺序存储二叉树,就是使用数组存储二叉树,并保留前中后序遍历的特点
class ArrayBinaryTree{
    private int[] arr;

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

    //前序遍历
    /**
     *
     * @param index 从数组的index下标开始遍历
     */
    public void preOrder(int index){
        //判断数组是否为空,为空则返回
        if(arr == null){
            return;
        }
        //输出当前结点的值
        System.out.println(arr[index]);
        //递归遍历左子树,在数组中左子树的下标是(2 * index + 1)
        if((2 * index + 1) < arr.length){//要判断下标是否越界数组
            preOrder(2 * index + 1);
        }
        //递归遍历左子树,在数组中左子树的下标是(2 * index + 2)
        if((2 * index + 2) < arr.length){
            preOrder(2 * index + 2);
        }
    }

    //我们一般都是从根节点开始遍历,所以一般index = 0
    //重载preOrder函数方便调用,不用传入参数
    public void preOrder(){
        preOrder(0);
    }

    //仿照前序遍历,写出中序遍历
    public void infixOrder(int index){
        if(arr == null){
            return;
        }
        if((2 * index + 1) < arr.length){
            infixOrder(2 * index + 1);
        }
        System.out.println(arr[index]);
        if((2 * index + 2) < arr.length){
            infixOrder(2 * index + 2);
        }
    }
    public void infixOrder(){
        infixOrder(0);
    }

    //后序遍历
    public void postOrder(int index){
        if(arr == null){
            return;
        }
        if((2 * index + 1) < arr.length){
            postOrder(2 * index + 1);
        }
        if((2 * index + 2) < arr.length){
            postOrder(2 * index + 2);
        }
        System.out.println(arr[index]);
    }
    public void postOrder(){
        postOrder(0);
    }
}

线索二叉树

package com.weeks.tree.threadedbinarytree;

/**
 * @author 达少
 * @version 1.0
 * 线索化二叉树
 */
public class ThreadedBinaryTreeDemo {
    public static void main(String[] args) {
        HeroNode node1 = new HeroNode(1, "tom");
        HeroNode node2 = new HeroNode(3, "jack");
        HeroNode node3 = new HeroNode(6, "smith");
        HeroNode node4 = new HeroNode(8, "milan");
        HeroNode node5 = new HeroNode(10, "adair");
        HeroNode node6 = new HeroNode(14, "john");

        //手动创建二叉树
        node1.setLeft(node2);
        node1.setRight(node3);
        node2.setLeft(node4);
        node2.setRight(node5);
        node3.setLeft(node6);
        ThreadedBinaryTree threadedBinaryTree = new ThreadedBinaryTree();
        threadedBinaryTree.setRoot(node1);

        //测试中序线索化二叉树{8, 3, 10, 1, 14, 6}
//        threadedBinaryTree.threaded();

        //输出node5的前驱和后继结点{}
        HeroNode node5Left = node5.getLeft();
        HeroNode node5Right = node5.getRight();
        System.out.println("node5Left=" + node5Left);
        System.out.println("node5Right=" + node5Right);
//
//        //测试线索化后线索化中序遍历线索化二叉树
//        threadedBinaryTree.infixOrder2();

        //前序线索化二叉树{1, 3, 8, 10, 16, 14}
    }
}

//定义二叉树类
class ThreadedBinaryTree{
    private HeroNode root;//根结点
    //用于线索化二叉树的时候,指向当前结点的前驱结点
    private HeroNode pre;

    public HeroNode getRoot() {
        return root;
    }

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

    //前序遍历
    public void preOrder(){
        if(root == null){
            return;
        }
        root.preOrder();
    }

    //中序遍历
    public void infixOrder(){
        if(root == null){
            return;
        }
        root.infixOrder();
    }

    //后序遍历
    public void postOrder(){
        if(root == null){
            return;
        }
        root.postOrder();
    }

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

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

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

    //删除结点
    public void delNode(int no){
        //判断二叉树是否为空
        if(root == null){
            return;
        }
        //判断根节点是否符合删除条件,符合则将整棵树置空后返回
        if(root.getNo() == no){
            root = null;
            return;
        }else{//否则执行HeroNode中的delNode操作
            root.delNode(no);
        }
    }

    //使用中序遍历线索化二叉树
    public void threaded(HeroNode node){
        //判断node是否为空
        if(node == null){
            return;
        }

        //中序线索化的三大步骤
        //1.递归线索化左子树
        threaded(node.getLeft());
        //2.处理当前结点(重点)
        if(node.getLeft() == null){//如果左指针为空,将其指向前驱结点
            node.setLeft(pre);
            node.setLeftType(1);//设置左指针类型为1
        }
        //如果前驱结点不为空,而且前驱结点的右指针为空,则让前驱结点的右指针指向当前结点
        if(pre != null && pre.getRight() == null){
            pre.setRight(node);
            pre.setRightType(1);//设置右指针类型为1
        }
        //将当前结点赋给前驱结点,向下移动
        pre = node;

        //3.递归处理右子树
        threaded(node.getRight());
    }

    //为了方便调用,重载threaded方法
    public void threaded(){
        this.threaded(root);
    }

    //因为经过线索化后二叉树的叶子结点左右指针发生了变化,不能再使用原来的中序遍历方式
    public void infixOrder2(){
        HeroNode node = root;//辅助遍历整棵二叉树
        //遍历
        while(node != null){
            //首先要找到左子树中leftType==1的叶子结点
            while(node.getLeftType() != 1){
                node = node.getLeft();
            }//当退出循环就找了
            //找到leftType == 1的叶子结点后,直接输出
            System.out.println(node);
            //当node的右指针域类型为1,就是rightType==1,时继续下移输出
            while(node.getRightType() == 1){
                node = node.getRight();
                System.out.println(node);
            }
            //当退出上面的循环时,证明右指针域指向的不是后继结点,所以要替换当前的node
            node = node.getRight();//替换node后开始下一次while循环
        }
    }
}

//定义树的结点对象类
class HeroNode{
    private int no;
    private String name;
    private HeroNode left;
    private HeroNode right;

    //定义左右指针的类型,约定:
    //如果左指针指针类型为0,则指向的是左子树;如果左指针类型为1,指向的就是前驱结点
    //如果右指针指针类型为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 + '\'' +
                '}';
    }

    //前序遍历
    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 找到就返回该结点,否则返回null
     */
    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;//返回不为空就是找打了,返回空就是没有找到
    }

    //中序查找
    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(this.no == no){
            return this;
        }
        return resNode;
    }

    //删除结点
    /**
     * 约定:
     * 如果删除的是叶子结点,则直接删除
     * 如果不是也只结点直接删除以该节点为父节点的子树
     */
    public void delNode(int no){
        /**
         * 1.因为要现在创建的二叉树是单向的,要删除只能找到父节点分别判断左右结点是否符合
         *   删除的条件,所以首先判断左子树是否有符合删除的条件的结点,递归实现
         * 2.接下来是递归判断右子树中是否有符合删除条件的结点
         */
        //判断该节点是否有左子树并判断左子树是否符合删除条件
        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);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值