算法与数据结构(一)——二叉树(全)

一、二叉树定义:

二叉树是树结构的一种,至于两者的定义看图即可:

1、树

在这里插入图片描述

2、二叉树

在这里插入图片描述

二、二叉树的创建

1、结点的实现

   和表示链表一样,我们可以使用一个内部类类来表示二叉树的一个节点:

//定义树节点
    public static class TreeNode{
        int val;
        TreeNode left,right;
        TreeNode(int val){ this.val = val;}

        TreeNode(int val, TreeNode left, TreeNode right) {
            this.val = val;
            this.left = left;
            this.right = right;
        }
    }

2、二叉树的构建

   创建好二叉树的结点之后,便需要通过结点创建二叉树。那么该如何创建二叉树呢?最简单的方法便是先创建出所有的结点,然后依次将所有的结点进行链接,当然该方法比较麻烦。其实在刷题过程中便发现题目的测试用例都是通过数组给出的,因此在这里给出了一种通过数组创建二叉树的方法:

//定义二叉树
    public static class BT{
        TreeNode root;        //给出二叉树的根结点
        BT(Integer[] arr){    //二叉树的构造方法,使用Integer数组,可以使用null
            int n = arr.length;
            ArrayList<TreeNode> nodes = new ArrayList<>();   //将数组中的元素转化为结点并保存在集合中
            for (int i = 0; i < n; i++) {
                if (arr[i]==null) nodes.add(null);
                else nodes.add(new TreeNode(arr[i],null,null));

            }
            LinkedList<TreeNode> queue = new LinkedList<>();
            TreeNode temp = nodes.get(0);
            boolean flag=true;
            //遍历结点集合
            for (int i = 1; i < n; i++) {
                if (flag){  //挂左子结点
                    temp.left=nodes.get(i);
                    if (nodes.get(i)!=null) queue.offer(nodes.get(i));
                    flag=false;
                }
                else {    //挂右子结点
                    temp.right=nodes.get(i);
                    if (nodes.get(i)!=null) queue.offer(nodes.get(i));
                    flag = true;
                    temp = queue.poll();   //改变悬挂点
                }
            }
            this.root = nodes.get(0);
        }

    }

三、二叉树的遍历

1、遍历分类

(1)前序遍历:先访问根节点,再访问左子树,最后访问右子树(中左右)
(2)中序遍历:先访问左子树,再访问根节点,最后访问右子树(左中右)
(3)后序遍历:先访问左子树,再访问右子树,最后访问根节点(左右中)
(4)层序遍历:由上到下,由左到右进行遍历
(5)Z型遍历:由上到下,左右交替

【注意】在进行遍历的时候需要用到递归的思想,例如要访问左子树,当左子树仍是一个二叉树时,便需要将其当做新的二叉树进行遍历

在这里插入图片描述

2、代码实现

(1)顺序遍历

   递归即可

//前、中、后序遍历
    public static void preTra(TreeNode root){
        if (root==null) return;
        System.out.println(root.val);
        preTra(root.left);
        preTra(root.right);
    }

(2)层序遍历

   可分为分层和不分层两种:分层指的是将不同层的元素相互隔开,分开保存;不分层指的是依次输出遍历结果,不同层之间不进行区分

//层序遍历(不分层)
    public static void layerTra(TreeNode root){
        if (root==null) return;
        LinkedList<TreeNode> Nodes = new LinkedList<>();
        Nodes.offer(root);
        while(!Nodes.isEmpty()){
            TreeNode temp = Nodes.poll();
            System.out.println(temp.val);
            if (temp.left!=null) Nodes.offer(temp.left);
            if (temp.right!=null) Nodes.offer(temp.right);
        }
    }
    //层序遍历(分层)
    public static List<List<Integer>> layerTra1(TreeNode root){
        if (root==null) return null;
        List<List<Integer>> result = new ArrayList<>();   //保存结果
        LinkedList<TreeNode> Nodes = new LinkedList<>();   //创建队列保存每一层的节点
        Nodes.offer(root);
        while(!Nodes.isEmpty()){
            List<Integer> res = new ArrayList<>();
            int n = Nodes.size();
            for (int i = 0; i < n; i++) {
                TreeNode temp = Nodes.poll();
                res.add(temp.val);
                if (temp.left!=null) Nodes.offer(temp.left);
                if (temp.right!=null) Nodes.offer(temp.right);
            }
            result.add(res);
        }
        return result;
    }

(3)Z型遍历

   在层序遍历的基础上加一个flag标志位,控制左右切换

//Z型遍历
    public static void zTra(TreeNode root){
        Queue<TreeNode> nodes = new LinkedList<>();
        nodes.offer(root);
        boolean flag =false;
        while (!nodes.isEmpty()){
            int n = nodes.size();
            ArrayList<Integer> res = new ArrayList<>();
            for (int i = 0; i < n; i++) {
                TreeNode temp = nodes.poll();
                res.add(temp.val);
                if (temp.left!=null) nodes.offer(temp.left);
                if (temp.right!=null) nodes.offer(temp.right);
            }
            if (flag) {
                for (Integer x : res) {
                    System.out.println(x);
                }
                flag = !flag;
            }
            else {
                for (int i = res.size()-1; i >=0; i--) {
                    System.out.println(res.get(i));
                }
                flag = !flag;
            }
        }
    }

四、二叉树的其他操作

1、左右翻转

//左右翻转
    public static TreeNode reverse(TreeNode root){
        if (root==null) return null;  //递归结束条件
        TreeNode temp = root.left;    //左右交换
        root.left = root.right;
        root.right = temp;
        reverse(root.left);           //递归调用
        reverse(root.right);
        return root;
    }

2、最大深度

//最大深度
    public static int maxDepth(TreeNode root){
        if (root==null) return 0;
        int left = maxDepth(root.left);
        int right = maxDepth(root.right);
        return Math.max(left,right)+1;
    }

3、最小深度

//最小深度
    public static int minDepth(TreeNode root){
        if (root==null) return 0;
        int left = minDepth(root.left);
        int right = minDepth(root.right);
        if (left==0) return right+1;
        else if (right==0) return left+1;
        else return Math.min(left,right)+1;
    }

五、下面给出整体的代码:

package binarytree;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class binarytree {

    public static void main(String[] args) {
        //测试函数
        Integer[] a = {1,2,3,null,null,4,5,6};
        Integer[] b = {3,9,20,null,null,15,7};
        BT bt = new BT(a);
        System.out.println(maxDepth(bt.root));
        System.out.println(minDepth(bt.root));
//        layerTra(bt.root);
//        System.out.println("===");
        /*
        List<List<Integer>> lists = layerTra1(bt.root);
        for (int i = 0; i < lists.size(); i++) {
            for (int j = 0; j < lists.get(i).size(); j++) {
                System.out.println(lists.get(i).get(j));
            }
            System.out.println("===");
        }
        */


    }



    //前序遍历
    public static void preTra(TreeNode root){
        if (root==null) return;
        System.out.println(root.val);
        preTra(root.left);
        preTra(root.right);

    }
    //层序遍历(不分层)
    public static void layerTra(TreeNode root){
        if (root==null) return;
        LinkedList<TreeNode> Nodes = new LinkedList<>();
        Nodes.offer(root);
        while(!Nodes.isEmpty()){
            TreeNode temp = Nodes.poll();
            System.out.println(temp.val);
            if (temp.left!=null) Nodes.offer(temp.left);
            if (temp.right!=null) Nodes.offer(temp.right);
        }
    }
    //层序遍历(分层)
    public static List<List<Integer>> layerTra1(TreeNode root){
        if (root==null) return null;
        List<List<Integer>> result = new ArrayList<>();   //保存结果
        LinkedList<TreeNode> Nodes = new LinkedList<>();   //创建队列保存每一层的节点
        Nodes.offer(root);
        while(!Nodes.isEmpty()){
            List<Integer> res = new ArrayList<>();
            int n = Nodes.size();
            for (int i = 0; i < n; i++) {
                TreeNode temp = Nodes.poll();
                res.add(temp.val);
                if (temp.left!=null) Nodes.offer(temp.left);
                if (temp.right!=null) Nodes.offer(temp.right);
            }
            result.add(res);
        }
        return result;
    }
    //Z型遍历
    public static void zTra(TreeNode root){
        Queue<TreeNode> nodes = new LinkedList<>();
        nodes.offer(root);
        boolean flag =false;
        while (!nodes.isEmpty()){
            int n = nodes.size();
            ArrayList<Integer> res = new ArrayList<>();
            for (int i = 0; i < n; i++) {
                TreeNode temp = nodes.poll();
                res.add(temp.val);
                if (temp.left!=null) nodes.offer(temp.left);
                if (temp.right!=null) nodes.offer(temp.right);
            }
            if (flag) {
                for (Integer x : res) {
                    System.out.println(x);
                }
                flag = !flag;
            }
            else {
                for (int i = res.size()-1; i >=0; i--) {
                    System.out.println(res.get(i));
                }
                flag = !flag;
            }
        }
    }


    //左右翻转
    public static TreeNode reverse(TreeNode root){
        if (root==null) return null;  //递归结束条件
        TreeNode temp = root.left;    //左右交换
        root.left = root.right;
        root.right = temp;
        reverse(root.left);           //递归调用
        reverse(root.right);
        return root;
    }

    //最大深度
    public static int maxDepth(TreeNode root){
        if (root==null) return 0;
        int left = maxDepth(root.left);
        int right = maxDepth(root.right);
        return Math.max(left,right)+1;
    }

    //最小深度
    public static int minDepth(TreeNode root){
        if (root==null) return 0;
        int left = minDepth(root.left);
        int right = minDepth(root.right);
        if (left==0) return right+1;
        else if (right==0) return left+1;
        else return Math.min(left,right)+1;
    }


    //定义树节点
    public static class TreeNode{
        int val;
        TreeNode left,right;
        TreeNode(int val){ this.val = val;}

        TreeNode(int val, TreeNode left, TreeNode right) {
            this.val = val;
            this.left = left;
            this.right = right;
        }
    }
    //定义二叉树
    public static class BT{
        TreeNode root;        //给出二叉树的根结点
        BT(Integer[] arr){    //二叉树的构造方法,使用Integer数组,可以使用null
            int n = arr.length;
            ArrayList<TreeNode> nodes = new ArrayList<>();   //将数组中的元素转化为结点并保存在集合中
            for (int i = 0; i < n; i++) {
                if (arr[i]==null) nodes.add(null);
                else nodes.add(new TreeNode(arr[i],null,null));

            }
            LinkedList<TreeNode> queue = new LinkedList<>();
            TreeNode temp = nodes.get(0);
            boolean flag=true;
            //遍历结点集合
            for (int i = 1; i < n; i++) {
                if (flag){  //挂左子结点
                    temp.left=nodes.get(i);
                    if (nodes.get(i)!=null) queue.offer(nodes.get(i));
                    flag=false;
                }
                else {    //挂右子结点
                    temp.right=nodes.get(i);
                    if (nodes.get(i)!=null) queue.offer(nodes.get(i));
                    flag = true;
                    temp = queue.poll();   //改变悬挂点
                }
            }
            this.root = nodes.get(0);
        }

    }


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值