栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

二叉树的基操

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

二叉树的基操

1.二叉树的创建

快速掌握为叉树的基本操作,这里只是创建一颗简单的二叉树,并不是二叉树的真正创建方式;后期会讲解二叉树的真正创建方式。

public class BinaryTree {
    public static class TreeNode {
        public char val;
        public TreeNode left;
        public TreeNode right;

        public TreeNode(char val) {
            this.val = val;
        }
    }
    //public TreeNode root;

    public TreeNode createTree() {
        TreeNode A = new TreeNode('A');
        TreeNode B = new TreeNode('B');
        TreeNode C = new TreeNode('C');
        TreeNode D = new TreeNode('D');
        TreeNode E = new TreeNode('E');
        TreeNode F = new TreeNode('F');
        TreeNode G = new TreeNode('G');
        return A;
    }
}

我们在了解完二叉树的性质后,就能知道,二叉树的定义是递归式的,因此后续基本操作都是按照该概念实现的。

2.二叉树的基操 2.1.二叉树的遍历

二叉树的遍历分为三种:

  • NLR :前序遍历( 先序遍历 )—— 访问根结点 ---> 根的左子树 ---> 根的右子树。(根左右)
  • LNR :中序遍历 —— 根的左子树 ---> 根节点 ---> 根的右子树。 (左根右)
  • LRN :后序遍历 (Postorder Traversal)—— 根的左子树 ---> 根的右子树 ---> 根节点。(左右根)

前序遍历:

    // 前序遍历
    public void preOrder(TreeNode root) {
        if(root == null) return;
        System.out.println(root.val);//根
        preOrder(root.left);//左
        preOrder(root.right);//右
    }

 中序遍历:

    // 中序遍历
    public void inOrder(TreeNode root) {
        if(root == null) return;
        preOrder(root.left);//左
        System.out.println(root.val);//根
        preOrder(root.right);//右
    }

 后序遍历:

    // 后序遍历
    public void postOrder(TreeNode root) {
        if(root == null) return;
        preOrder(root.left);//左
        preOrder(root.right);//右
        System.out.println(root.val);//根
    }

分享两种思路(以后序遍历为例):遍历思路和子问题思路

遍历思路:

    List ret = new ArrayList<>();
    //数组放外面,是为了防止每次递归都重新开辟空间
    public List postOrderTraversal(TreeNode root) {
        if(root == null) return ret;
        ret.add(root.val);
        postOrderTraversal(root.left);
        postOrderTraversal(root.right);
        return ret;
    }

 子问题思路:

    public List postOrderTraversal(TreeNode root) {
        List ret = new ArrayList<>();
        //数组如果放在里边,就需要接收返回值了,否则每次都重新创建了一个新的数组
        if(root == null) return ret;
        List leftTree = postOrderTraversal(root.left);
        ret.addAll(leftTree);
        List rightTree = postOrderTraversal(root.right);
        ret.addAll(rightTree);
        return ret;
    }

2.2.二叉树的基本操作 2.2.1.获取树中节点的个数---遍历思路
    public static int nodeSize = 0;
    public int size(TreeNode root) {
        if(root == null) return 0;
        nodeSize++;//把每一颗子树的根都加起来
        size(root.left);
        size(root.right);
        return nodeSize;
    }

2.2.1.获取树中节点的个数---子问题思路

    public int size2(TreeNode root) {
        if(root == null) return 0;
        //树的结点个数 = 左子树结点数 + 右子树结点数 + 根(1)
        return size2(root.left) + size2(root.right) + 1;
    }

2.2.2.获取叶子节点的个数---遍历思路

    public static int leafSize = 0;
    public int getLeafNodeCount(TreeNode root) {
        if(root == null) return 0;
        //叶子结点:左孩子和右孩子都为null
        if(root.left == null && root. right == null) {
            leafSize++;
        }
        getLeafNodeCount(root.left);
        getLeafNodeCount(root.right);
        return leafSize;
    }

2.2.2.获取叶子节点的个数---子问题思路        

    public int getLeafNodeCount2(TreeNode root) {
        if(root == null) return 0;
        if(root.left == null && root.right == null) {
            return 1;
        }
        return getLeafNodeCount2(root.left) + getLeafNodeCount2(root.right);
    }

2.2.3.获取第 K 层节点的个数 
    public int getKLevelNodeCount(TreeNode root, int k) {
        if(root == null) return 0;
        if(k == 1) return 1;
        //第 k 层结点个数等于 以root的左子树为根结点的这棵树的第 k-1 层 + 以root的右子树为根结点的这棵树的第 k-1 层
        // 依次类推,k == 1 的时候,这棵树只有根,左右子树都为空,那么就返回 1
        return getKLevelNodeCount(root.left, k - 1) + getKLevelNodeCount(root.right, k - 1);
    }

2.2.4获取二叉树的高度

    public int getHeight(TreeNode root) {
        if(root == null) return 0;
        if(root.left == null && root.right == null) {
            return 1;
        }
        int leftH = getHeight(root.left);
        int rightH = getHeight(root.right);
        //二叉树的高度 = 左子树高度 和 右子树高度 中较大的一个 + 1
        return leftH > rightH ? leftH + 1 : rightH + 1;
    }

这里的求左右子树的高度时,建议接收值,不然在三木操作符中会重复计算,导致时间浪费,在oj上可能就会跑不过。


2.2.5.检测值为value的元素是否存在

    public TreeNode find(TreeNode root, char val) {
        if(root == null) return null;
        if(root.val == val) return root;
        //left和right只有 root 和 null两种可能,先把左边找完,如果不为空,就返回
        TreeNode left = find(root.left, val);
        if(left != null) {
            return left;
        }
        //右边和左边一样
        TreeNode right = find(root.right, val);
        if(right != null) {
            return right;
        }
        return null;
    }

 2.2.6.层序遍历---简易版

    public void levelOrder(TreeNode root) {
        if(root == null) return;
        Queue queue = new LinkedList<>();
        queue.offer(root);
        //队列不为空,就弹出一个元素,并输出
        while(!queue.isEmpty()) {
            TreeNode cur = queue.poll();
            System.out.print(cur.val + " ");
            //弹出的元素左右子树不为空,就依次入队
            if(cur.left != null) {
                queue.offer(cur.left);
            }
            if(cur.right != null) {
                queue.offer(cur.right);
            }
        }
    }

层序遍历需要用到队列,每一次出队后,就把出队元素的左右元素入队(不为空就入)

 2.2.7.层序遍历---提高难度

public List> levelOrder(TreeNode root) {
    List> ret = new ArrayList<>();
    if(root == null) return ret;

    Queue queue = new LinkedList<>();
    queue.offer(root);

    while(!queue.isEmpty()) {
        //二叉树当前层的元素集合
        List list = new ArrayList<>();
        int size = queue.size();
        //size就是二叉树当前层的元素个数
        while(size != 0) {
            TreeNode cur = queue.poll();
            list.add(cur.val);
            size--;
            if(cur.left != null) {
                queue.offer(cur.left);
            }
            if(cur.right != null) {
                queue.offer(cur.right);
            }
        }
        ret.add(list);
    }
    return ret;
}

当求一棵二叉树的层序遍历时,返回值改为二维数组,则每一层都可以看成是一个一维数组,这样的话,我们就可以在队列不为空这个循环里嵌套一个循环,用每一层的元素个数来控制循环;


 2.2.8.判断一棵树是不是完全二叉树

    public boolean isCompleteTree(TreeNode root) {
        if(root == null) return false;
        Queue queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            TreeNode cur = queue.poll();
            if(cur != null) {
                queue.offer(cur.left);
                queue.offer(cur.right);
            }else {
                break;
            }
        }
        //第2次遍历队列 判断队列当中 是否存在非空的元素
        while (!queue.isEmpty()) {
            TreeNode cur = queue.peek();
            if(cur == null) {
                queue.poll();
            }else {
                return false;
            }
        }
        return true;
    }

分析:判断一棵树是不是完全二叉树,也是要用到队列,类似于层序遍历,但是这里不同的是,左右子树为空也入队,null也是可以入队的;当弹出一个元素是 null 时,如果队里的元素全为 null,则说明它是一颗完全二叉树,,当然我们没有这种判断条件,所以这样做,当弹出的元素为 null 时,我们继续弹元素,如果为 null ,一直弹,直到队空;否则,就像图中右边的情况,弹出一个元素为空时,队里还有一个不为空,此时一定不是完全二叉树,,,

谢谢观看!!!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/933666.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号