树-java语言描述

1、树的一些基本概念
  • 树:一种数据结构,是由 n个有限的节点组成的一个具有层次关系的集合
  • 节点:组成树的部分
  • 父节点:该节点的上一个节点
  • 子节点:该节点的下一个节点
  • 根节点:没有父节点的节点
  • 叶子节点:没有子节点的节点
  • 分支节点:有子节点的节点
  • 节点的权:该节点里面的值
  • 路径:从根节点到当前节点的路线
  • 层:根节点的层次为 1,其余节点等于该节点的父节点加 1
  • 子树:从当前节点看,以它的一个子节点有根节点的树
  • 树的高度:树中节点的最大层次
  • 森林:0个或多个不相交的树组成,对森林加上一个跟,就成为了树,去掉跟,树就是森林
  • 二叉树:每个节点最多只有两个节点的树
  • 满二叉树:所有的叶子节点都在最后一层,并且节点的总数为 2^n - 1 (n为层数)
  • 完全二叉树:所有的叶子节点都在最后一层或者是倒数第二层,并且最后一层的叶子节点都是左连续,倒数第二层的节点都是右连续
  • 前序遍历:先输出父节点,在输出左节点,在输出右节点
  • 中序遍历:先输出左节点,在输出父节点,在输出右节点
  • 后序遍历:先输出左节点,在输出右节点,在输出父节点
  • 前序查找:
    • 1、先判断当前节点是否是要查找的节点,如果是,则返回当前节点
    • 2、如果不是,则判断当前节点的左节点是否为空,若不为空,则递归前序查找,如果递归找到了要查找的节点,则返回
    • 3、如果没找到,则判断当前节点的右节点是否为空,若不为空,则递归前序查找,如果递归找到了要查找的节点,则返回
    • 4、如果还是没有找到,则表示当前树中没有符合要查找的节点,返回null
  • 中序查找:
    • 1、先判断当前节点的左节点是否为空,若不为空,则递归中序查找,如果递归找到了要查找的节点,则返回
    • 2、如果没找到,则与当前节点进行比较,如果符合要查找的条件,则返回当前节点
    • 3、如果不符合,则判断当前节点的右节点是否为空,若不为空,则递归中序查找,如果递归找到了要查找的节点,则返回
    • 4、如果还是没有找到,则表示当前树中没有符合要查找的节点,返回null
  • 后序查找:
    • 1、先判断当前节点的左节点是否为空,若不为空,则递归后序查找,如果递归找到了要查找的节点,则返回
    • 2、如果没找到,则判断当前节点的右节点是否为空,若不为空,则递归后序查找,如果递归找到了要查找的节点,则返回
    • 3、如果没找到,则与当前节点进行比较,如果符合,则返回当前节点
    • 4、如果还是没有找到,则表示当前树中没有符合要查找的节点,返回null
2、树的性质
  • 二叉树的第 i层上的节点数目最多为 2i - 1个节点(i >= 1)
  • 深度为 k的二叉树至多有 2k - 1个节点(k >= 1)
  • 包含 n个节点的二叉树的高度至少为 (log2n) + 1
  • 在任意一颗二叉树之中,若终端节点的个数为 n,度为 2的节点数为 m,则 n = m + 1
  • 二叉排序树之中,若任意节点的子节点不为空,则左子树上所有节点的值都小于该节点,右子树上的所有节点 的值都大于该节点
  • 没有键值相等的节点
3、对树的一些基本操作
3.1、前序遍历
//前序遍历
    public void frontOrder() {
        //首先输出父节点
        System.out.println(this);
        //如果当前节点的左子树不为空,递归进行左子树的遍历
        if (this.getLeft() != null) {
            this.left.frontOrder();
        }
        //如果当前节点的右子树不为空,递归进行右子树的遍历
        if (this.getRight() != null) {
            this.right.frontOrder();
        }
    }

​ 中序遍历与后序遍历其实和前序遍历是一样的,只是一些代码的顺序稍微改变了而已

3.2、中序遍历
3.3、后序遍历
3.4、前序查找
	/**
     * 前序遍历查找的方法
     *
     * @param no 需要查找的节点的 no
     * @return 如果找到了就返回该 Node,如果没找到,则返回null
     */
    public Node frontOrderSearch(int no) {
        //定义一个临时接收返回结果的变量
        Node node = null;
        //先判断当前节点是否等于要查找的节点,如果相等,则返回当前节点
        if (this.no == no) {
            return this;
        }
        //如果不想等,则判断当前节点的左节点是否为空,若不为空,则递归前序查找
        if (this.left != null) {
            node = this.left.frontOrderSearch(no);
        }
        //如果递归找到了要查找的节点,则返回
        if (node != null) {
            return node;
        }
        //如果没找到,则判断当前节点的右节点是否为空,若不为空,则递归前序查找
        if (this.right != null) {
            node = this.left.frontOrderSearch(no);
        }
        //如果递归找到了要查找的节点,则返回,如果还是没有找到,则表示当前树中没有符合要查找的节点,返回null
        return node;
    }

​ 中序查找与后序后序其实和前序查找是一样的,只是一些代码的顺序稍微改变了而已

3.5、中序查找
3.6、后序查找
3.7、添加节点
//先创建一个二叉树
BinaryTree binaryTree = new BinaryTree();
//创建我们所需要的节点,第一个为根节点
Node root = new Node(1, "黑猫");
Node node2 = new Node(2, "白猫");
Node node3 = new Node(3, "黄猫");
Node node4 = new Node(4, "绿猫");

/*
目前我只会手动添加
*/
binaryTree.setRoot(root);
root.setLeft(node2);
root.setRight(node3);
node3.setRight(node4);
3.7、删除节点
	/**
     * 删除节点的方法
     * 直接将要删除的节点与其子树一起删除了
     *
     * @param no 需要删除的节点的编号
     */
    public void deleteNode(int no) {
        //如果当前节点的左节点不为空,且当前节点的左节点就是需要删除的节点,而应该是去判断当前节点的子节点是否是需要删除的
        if (this.left != null && this.left.no == no) {
            this.left = null;
            return;
        }
        //如果当前节点的右节点不为空,且当前节点的右节点就是需要删除的节点,那么直接将 this.right = null即可(结束递归)
        if (this.right != null && this.right.no == no) {
            this.right = null;
            return;
        }
        //对左子树进行递归删除
        if (this.left != null) {
            this.left.deleteNode(no);
        }
        //对右子树进行递归删除
        if (this.right != null) {
            this.right.deleteNode(no);
        }
    }
4、完整源码
public class TreeDemo {
    public static void main(String[] args) {
        //先创建一个二叉树
        BinaryTree binaryTree = new BinaryTree();
        //创建我们所需要的节点,第一个为根节点
        Node root = new Node(1, "黑猫");
        Node node2 = new Node(2, "白猫");
        Node node3 = new Node(3, "黄猫");
        Node node4 = new Node(4, "绿猫");

        binaryTree.setRoot(root);
        root.setLeft(node2);
        root.setRight(node3);
        node3.setRight(node4);

        //遍历树
        System.out.println("前序遍历:");
        binaryTree.frontOrder();
        System.out.println("中序遍历:");
        binaryTree.middleOrder();
        System.out.println("后序遍历:");
        binaryTree.rearOrder();

        System.out.println("-----------------------------");

        //查找树
        System.out.println("前序查找:");
        Node node = binaryTree.frontOrderSearch(1);
        if (node != null) {
            System.out.println("该编号信息为\n编号:" + node.getNo() + " 名字:" + node.getName());
        } else {
            System.out.println("没找到");
        }
        System.out.println("中序查找:");
        binaryTree.middleOrderSearch(1);
        if (node != null) {
            System.out.println("该编号信息为\n编号:" + node.getNo() + " 名字:" + node.getName());
        } else {
            System.out.println("没找到");
        }
        System.out.println("后序查找:");
        binaryTree.rearOrderSearch(1);
        if (node != null) {
            System.out.println("该编号信息为\n编号:" + node.getNo() + " 名字:" + node.getName());
        } else {
            System.out.println("没找到");
        }

        System.out.println("-----------------------------");

        //删除节点
        System.out.println("删除前,使用前序遍历:");
        binaryTree.frontOrder();
        binaryTree.deleteNode(2);
        System.out.println("删除后,使用前序遍历:");
        binaryTree.frontOrder();

        System.out.println("-----------------------------");
    }
}

//定义一个二叉树
class BinaryTree {
    //定义一个根节点
    private Node root;

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

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

    //中序遍历
    public void middleOrder() {
        if (this.root != null) {
            this.root.middleOrder();
        } else {
            System.out.println("该二叉树为空!");
        }
    }

    //后序遍历
    public void rearOrder() {
        if (this.root != null) {
            this.root.rearOrder();
        } else {
            System.out.println("该二叉树为空!");
        }
    }

    //前序查找
    public Node frontOrderSearch(int no) {
        if (root != null) {
            return root.frontOrderSearch(no);
        } else {
            return null;
        }
    }

    //中序查找
    public Node middleOrderSearch(int no) {
        if (root != null) {
            return root.middleOrderSearch(no);
        } else {
            return null;
        }
    }

    //后序查找
    public Node rearOrderSearch(int no) {
        if (root != null) {
            return root.rearOrderSearch(no);
        } else {
            return null;
        }
    }

    //删除节点
    public void deleteNode(int no){
        if (root != null){
            //如果只有一个root节点,这里立即判断root是不是就是要删除的节点
            if (root.getNo() == no){
                root = null;
            }else {
                //递归删除
                root.deleteNode(no);
            }
        }else {
            System.out.println("空树,不能删除!");
        }
    }
}

//创建一个节点类
class Node {
    private int no;
    private String name;
    //指向该节点的左节点,默认为空
    private Node left;
    //指向该节点的右节点,默认为空
    private Node right;

    public Node(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 Node getLeft() {
        return left;
    }

    public void setLeft(Node left) {
        this.left = left;
    }

    public Node getRight() {
        return right;
    }

    public void setRight(Node right) {
        this.right = right;
    }

    @Override
    public String toString() {
        return "Node{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }

    //前序遍历
    public void frontOrder() {
        //首先输出父节点
        System.out.println(this);
        //如果当前节点的左子树不为空,递归进行左子树的遍历
        if (this.getLeft() != null) {
            this.left.frontOrder();
        }
        //如果当前节点的右子树不为空,递归进行右子树的遍历
        if (this.getRight() != null) {
            this.right.frontOrder();
        }
    }

    //中序遍历
    public void middleOrder() {
        //如果当前节点的左子树不为空,递归进行左子树的遍历
        if (this.getLeft() != null) {
            this.left.middleOrder();
        }
        //输出父节点
        System.out.println(this);
        //如果当前节点的右子树不为空,递归进行右子树的遍历
        if (this.getRight() != null) {
            this.right.middleOrder();
        }
    }

    //后序遍历
    public void rearOrder() {
        //如果当前节点的左子树不为空,递归进行左子树的遍历
        if (this.getLeft() != null) {
            this.left.rearOrder();
        }
        //如果当前节点的右子树不为空,递归进行右子树的遍历
        if (this.getRight() != null) {
            this.right.rearOrder();
        }
        //输出父节点
        System.out.println(this);
    }

    /**
     * 前序遍历查找的方法
     *
     * @param no 需要查找的节点的 no
     * @return 如果找到了就返回该Node,如果没找到,则返回null
     */
    public Node frontOrderSearch(int no) {
        //定义一个临时接收返回结果的变量
        Node node = null;
        //先判断当前节点是否等于要查找的节点,如果相等,则返回当前节点
        if (this.no == no) {
            return this;
        }
        //如果不想等,则判断当前节点的左节点是否为空,若不为空,则递归前序查找
        if (this.left != null) {
            node = this.left.frontOrderSearch(no);
        }
        //如果递归找到了要查找的节点,则返回
        if (node != null) {
            return node;
        }
        //如果没找到,则判断当前节点的右节点是否为空,若不为空,则递归前序查找
        if (this.right != null) {
            node = this.left.frontOrderSearch(no);
        }
        //如果递归找到了要查找的节点,则返回,如果还是没有找到,则表示当前树中没有符合要查找的节点,返回null
        return node;
    }

    /**
     * 中序遍历查找的方法
     *
     * @param no 需要查找的节点的 no
     * @return 如果找到了就返回该Node,如果没找到,则返回null
     */
    public Node middleOrderSearch(int no) {
        //定义一个临时接收返回结果的变量
        Node node = null;
        //先判断当前节点的左节点是否为空,若不为空,则递归前序查找
        if (this.left != null) {
            node = this.left.middleOrderSearch(no);
        }
        //如果递归找到了要查找的节点,则返回
        if (node != null) {
            return node;
        }
        //如果没找到,则判断当前节点是否等于要查找的节点,如果相等,则返回当前节点
        if (this.no == no) {
            return this;
        }
        //如果没找到,则判断当前节点的右节点是否为空,若不为空,则递归前序查找
        if (this.right != null) {
            node = this.left.middleOrderSearch(no);
        }
        //如果递归找到了要查找的节点,则返回,如果还是没有找到,则表示当前树中没有符合要查找的节点,返回null
        return node;
    }

    /**
     * 后序遍历查找的方法
     *
     * @param no 需要查找的节点的 no
     * @return 如果找到了就返回该Node,如果没找到,则返回null
     */
    public Node rearOrderSearch(int no) {
        //定义一个临时接收返回结果的变量
        Node node = null;
        //先判断当前节点的左节点是否为空,若不为空,则递归前序查找
        if (this.left != null) {
            node = this.left.rearOrderSearch(no);
        }
        //如果递归找到了要查找的节点,则返回
        if (node != null) {
            return node;
        }
        //如果没找到,则判断当前节点的右节点是否为空,若不为空,则递归前序查找
        if (this.right != null) {
            node = this.left.rearOrderSearch(no);
        }
        //如果没找到,则判断当前节点是否等于要查找的节点,如果相等,则返回当前节点
        if (this.no == no) {
            return this;
        }
        //如果递归找到了要查找的节点,则返回,如果还是没有找到,则表示当前树中没有符合要查找的节点,返回null
        return node;
    }

    /**
     * 删除节点的方法
     *
     * @param no 需要删除的节点的编号
     */
    public void deleteNode(int no) {
        //如果当前节点的左节点不为空,且当前节点的左节点就是需要删除的节点,而应该是去判断当前节点的子节点是否是需要删除的
        if (this.left != null && this.left.no == no) {
            this.left = null;
            return;
        }
        //如果当前节点的右节点不为空,且当前节点的右节点就是需要删除的节点,那么直接将 this.right = null即可(结束递归)
        if (this.right != null && this.right.no == no) {
            this.right = null;
            return;
        }
        //对左子树进行递归删除
        if (this.left != null) {
            this.left.deleteNode(no);
        }
        //对右子树进行递归删除
        if (this.right != null) {
            this.right.deleteNode(no);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值