二叉树的构建(java基于数组)

前言

        二叉树在算法中是经常考察的点,但是要在本地测试的话,就必须自己构建二叉树。在算法题中,一般给我们的都是一个数组,或者是二叉树的形状。因此,需要将数组转换为二叉树,这样才能测试出自己的代码是否符合题意。

构建基础知识

我采用的是完全二叉树的方式进行构建二叉树的,因此需要知道完全二叉树的性质:

        对于完全二叉树,若从上至下,从左至右,并从1开始进行编号,规则如下:

        编号为 i 的节点                

  1. 其左孩子的编号必为 2*i
  2. 其右孩子的编号必为 2*i + 1         

构建事项

由于我采用的是数组实现,因此与基本的性质有一些差别,这是因为数组的下标是从0开始计算的,从而规则更改为:

        编号为  i  的节点

  1. 其左孩子的编号必为 2 * i + 1
  2. 其右孩子的编号必为 2 * i + 2 

正式构建

构建一般的(int)二叉树

说明:

        因为一般的算法题中是以int 数组为代表的考题,因此将其单独提出来

构建二叉树节点

代码实现

public class TreeNode {
    // 节点数据
    public int val;
    // 左节点 遍历
    public TreeNode left;
    // 右节点
    public TreeNode right;
    public TreeNode() {
    }
    public TreeNode(int val) {
        this.val = val;
    }
}

二叉树构建方法

代码实现

   public TreeNode intArrayToBTree(int [] arrs) {
        // 判空处理,返回空节点
        if (arrs == null || arrs.length == 0) {
            return new TreeNode();
        }
        // 创建和数组长度相同的集合
        List<TreeNode> nodes = new ArrayList<>(arrs.length);
        // 遍历数组,将数组元素转为集合节点
        for (int obj : arrs) {
            TreeNode treeNode = new TreeNode();
            treeNode.val = obj;
            nodes.add(treeNode);
        }
        //  按照完全二叉树的规则构建,数组中的后半部分元素都是叶子节点,它们没有左右子节点。所以循环只需要处理前半部分的非叶子节点即可。
        //  i < arrs.length/2 - 1  能够将所有左右子节点不为null的元素给遍历出来,剩下最后一个(在左节点上)或者最后两个(在右节点上)
        //  保证循环只在前半部分有效的节点范围内进行迭代,避免处理不必要的叶子节点。
        for (int i = 0; i < arrs.length/2 - 1; i++) {
            TreeNode node = nodes.get(i);
            // 首先,由于是通过数组构建的二叉树(数组下标从0开始)
            // 其次,由完全二叉树的性质(从1开始计数,左孩子为2i,右孩子为2i  +1 )  再结合 数组下标0 开始计数 可知:
            // 树的左节点为 2i +1;树的右节点为:2i +2
            node.left = nodes.get(i*2 + 1);
            node.right = nodes.get(i*2 + 2);
        }
        // 只有当总节点数是奇数时,最后一个父节点才有右子节点
        int lastPNodeIndex = arrs.length/2 - 1;
        TreeNode lastPNode = nodes.get(lastPNodeIndex);
        // 左孩子节点
        lastPNode.left = nodes.get(lastPNodeIndex*2 + 1);
        if (arrs.length%2 != 0) {
            lastPNode.right = nodes.get(lastPNodeIndex*2 + 2);
        }

        return nodes.get(0);
    }

测试方法

代码实现 


    public static void main(String[] args) {
        int [] arr = {1,3,2,5,3,9};
        TreeNode treeNode = new TreeNode();
        TreeNode root = treeNode.intArrayToBTree(arr);
    }

测试过程

使用Debug模式运行(主要看fori循环那里)

在经过第一次的循环(将数组元素转为节点元素的循环)

        由于QQ长截图失效,将其截图为两张图,其实最主要的是观察第一个节点的变化,之后就直接第一个节点变化的值。 

        在第二个for循环开始前,需要关注一下循环判断条件

         i < arrs.length/2 - 1

         i < arrs.length/2 - 1 能够将所有左右子节点都不为null的元素给遍历出来,直至叶子节点,剩下最后一个叶子节点(在左节点上)或者最后两个叶子节点(在右节点上)

        这个条件是为了保证循环只在前半部分有效的节点范围内进行迭代,避免处理不必要的叶子节点。

 进入第一次for循环(i = 0)

 经过第一次循环(i = 0),可知根节点为1,其左节点为3(其下还没遍历出左右孩子),其右节点为2(其下还没遍历出左右孩子)

 进入第二次for循环(i = 1)

第 二次循环确定了根节点1的左孩子 的 左右孩子的值(也就是在第一次遍历基础上,得到遍历左节点3的左右孩子的值),从结果中可知,根节点的右孩子在这一次循环中没有添加进来,因为默认一次只添加左右孩子两个值,而节点9 是最后一个值,没有满足循环条件,因此右节点没有变化。

        当i = 1 结束时,会进行 i++ 操作,操作完成后 i = 2,不满足循环条件, 循环对于最后一个节点9,需要对其进行判断

        int lastPNodeIndex = arrs.length/2 - 1;
        TreeNode lastPNode = nodes.get(lastPNodeIndex);
        // 左孩子节点
        lastPNode.left = nodes.get(lastPNodeIndex*2 + 1);
        // 只有当总节点数是奇数时,最后一个父节点才有右子节点
        if (arrs.length%2 != 0) {
            lastPNode.right = nodes.get(lastPNodeIndex*2 + 2);
        }

测试结果:

根节点:       1        

第一层节点:3        2

第二层节点:5        3        9

构成的完全二叉树:

                         1

                       /    \

                     3      2

                   /    \    /  \

                  5    3  9   (null)

构建特殊的(Object) 二叉树

        有些算法场景也会用到其他类型作为数据域的节点构成的二叉树,因此也在上面基础上将int类的的数据节点改为Object类型的数据节点,其实现方法大同小异。

构建二叉树节点

public class TreeNode {
    // 节点数据
    public Object data;
    // 左节点 遍历
    public TreeNode left;
    // 右节点
    public TreeNode right;

    public TreeNode() {
    }

    public TreeNode(Object data) {
        this.data = data;
    }
    public TreeNode(Object data, TreeNode left, TreeNode right) {
        this.data = data;
        this.left = left;
        this.right = right;
    }
}

 二叉树构建方法

   /**
     * 数组遍历构成二叉树
     * @param arrs 数组
     * @return 二叉树根节点
     */
    public TreeNode arrayToBTree(Object[] arrs) {
        if (arrs == null || arrs.length == 0) {
            return new TreeNode();
        }

        List<TreeNode> nodes = new ArrayList<>(arrs.length);
        for (Object obj : arrs) {
            TreeNode treeNode = new TreeNode();
            treeNode.data = obj;
            nodes.add(treeNode);
        }

        for (int i = 0; i < arrs.length/2 - 1; i++) {
            TreeNode node = nodes.get(i);
            node.left = nodes.get(i*2 + 1);
            node.right = nodes.get(i*2 + 2);
        }
        // 只有当总节点数是奇数时,最后一个父节点才有右子节点
        int lastPNodeIndex = arrs.length/2 - 1;
        TreeNode lastPNode = nodes.get(lastPNodeIndex);
        lastPNode.left = nodes.get(lastPNodeIndex*2 + 1);
        if (arrs.length%2 != 0) {
            lastPNode.right = nodes.get(lastPNodeIndex*2 + 2);
        }

        return nodes.get(0);
    }

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
构建二叉树算法可以使用递归或迭代的方式实现。 以下是使用递归方式构建二叉树的示例代码: ``` class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } } public class BinaryTree { public TreeNode buildTree(int[] preorder, int[] inorder) { if (preorder == null || inorder == null || preorder.length != inorder.length) { return null; } return buildTreeHelper(preorder, inorder, 0, preorder.length - 1, 0, inorder.length - 1); } private TreeNode buildTreeHelper(int[] preorder, int[] inorder, int preStart, int preEnd, int inStart, int inEnd) { if (preStart > preEnd || inStart > inEnd) { return null; } int rootVal = preorder[preStart]; int rootIndex = 0; for (int i = inStart; i <= inEnd; i++) { if (inorder[i] == rootVal) { rootIndex = i; break; } } int leftSize = rootIndex - inStart; TreeNode root = new TreeNode(rootVal); root.left = buildTreeHelper(preorder, inorder, preStart + 1, preStart + leftSize, inStart, rootIndex - 1); root.right = buildTreeHelper(preorder, inorder, preStart + leftSize + 1, preEnd, rootIndex + 1, inEnd); return root; } } ``` 以上代码中,`buildTree`方法接受两个数组,一个是先序遍历序列,一个是中序遍历序列。通过先序遍历序列的第一个节点确定根节点,在中序遍历序列中找到根节点的位置,根节点左边的节点为左子树,右边的节点为右子树。递归调用`buildTreeHelper`方法建立左右子树,并将其连接到根节点上。 以下是使用迭代方式构建二叉树的示例代码: ``` class TreeNode { int val; TreeNode left; TreeNode right; TreeNode(int x) { val = x; } } public class BinaryTree { public TreeNode buildTree(int[] preorder, int[] inorder) { if (preorder == null || inorder == null || preorder.length != inorder.length) { return null; } Stack<TreeNode> stack = new Stack<>(); TreeNode root = new TreeNode(preorder[0]); stack.push(root); int inorderIndex = 0; for (int i = 1; i < preorder.length; i++) { TreeNode node = stack.peek(); if (node.val != inorder[inorderIndex]) { node.left = new TreeNode(preorder[i]); stack.push(node.left); } else { while (!stack.isEmpty() && stack.peek().val == inorder[inorderIndex]) { node = stack.pop(); inorderIndex++; } node.right = new TreeNode(preorder[i]); stack.push(node.right); } } return root; } } ``` 以上代码中,使用栈来辅助构建二叉树。先将先序遍历序列的第一个节点作为根节点入栈,然后依次遍历先序遍历序列中的每个节点,如果当前节点不等于中序遍历序列中的节点,则表示当前节点是根节点的左子树,将其作为左子节点入栈;否则,不断弹出栈顶元素,直到栈顶元素等于中序遍历序列中的节点,表示当前节点是某个节点的右子树,将其作为右子节点入栈。最终返回根节点。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值