把二叉树打印成多行

题目

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

思路1

层序遍历,只有一点需要考虑,就是如何把层序遍历序列按层分开来,因为返回的是每一层的遍历序列。

最简单的做法是遍历当前层的时候就逐步确定下一层最右边的结点(遍历的过程中,下一层的最右结点一直在更新),这样当这一层遍历完时,下一层的最右结点也就确定了,这样当遍历下一层的时候就有了一个终点,这样子就完成了分层。

    /**
     * 解法1:记录每层的最右节点:
     *      遍历当前层的时候就逐步确定下一层最右边的结点(遍历的过程中,下一层的最右结点一直在更新),
     *      这样当这一层遍历完时,下一层的最右结点也就确定了,这样当遍历下一层的时候就有了一个终点,
     *      这样子就完成了分层。
     */
    public List<List<Integer>> levelOrder2(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        ArrayList<Integer> arr = new ArrayList<>();
        if (root == null)
            return result;
        TreeNode pre = root,  now = null ;
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        while (!q.isEmpty()) {
            TreeNode node = q.poll();
            arr.add(node.val);
            if (node.left != null) {
                q.offer(node.left);
                now = node.left;
            }
            if (node.right != null) {
                q.add(node.right);
                now = node.right;
            }
            //当前遍历节点是某层的最右节点时就添加arr到result中,并清空arr以便接着存下一层
            if (pre == node) {
                result.add(arr);
                /*
                 * 这里直接用clear错误,因为这里arr指向的这个ArrayList<Integer>对象现在保存在result中,
                 * arr.clear()意味着把这个对象里的内容清空了,所以result里的对象就为空了!
                 * 应该将arr再重新指向一个新的ArrayList对象即可!
                 */
                //arr.clear();
                arr = new ArrayList<>();
                //pre更新为下一层节点的最右节点,即为node.right如果node.rigth存在的话!
                pre = now;
            }
        }
        return result;
    }

思路2

使用一个队列,根据队列中元素的个数来确定分层,当队列中的某一层元素全部遍历完(遍历完就会弹出队列)后,队列中就只有下一层的元素,所以,可以依据这个来分层。

    /**
     * 解法2:使用一个队列
     *      根据队列中元素的个数来确定分层,当队列中的某一层元素全部遍历完(遍历完就会弹出队列)后,
     *      队列中就只有下一层的元素此时队列长度length就是下一层元素个数,然后再遍历这一层(即遍历length长度)时将下一层入队。
     */
    public List<List<Integer>> levelOrder3(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        if (root == null) return result;
        //只用一个队列来做
        Queue<TreeNode> q = new LinkedList<>();
        q.offer(root);
        while (!q.isEmpty()) {
            List<Integer>  oneLevel = new ArrayList<>();
            int size = q.size();
            for (int i = 0; i < size; ++i) {
                //获取队头元素而不移出该元素,使用element()或者peek(),获取并移出使用poll()
                TreeNode node = q.poll();
                oneLevel.add(node.val);
                if (node.left!=null) q.offer(node.left);
                if (node.right!=null) q.offer(node.right);
            }
            result.add(oneLevel);
        }
        return result;
    }

思路3

思路2需要在队列中确定某一层的个数,这个操作可以用两个队列来实现,也就是遍历一个队列的所有孩子放到另一个队列中;遍历另一个队列时,又把另一个队列中的所有孩子又放回来这个队列,这样也实现了分层。而且,两个队列始终有一个队列保持为空。这样子的操作叫滚动队列。

    /**
     * 解法3:使用两个队列current和next
     *      只用一个队列要每次记录下一层的个数,这个操作其实可以用两个队列来实现,也就是遍历一个队列的所有孩子放到另一个队列中;
     *      遍历另一个队列时,又把另一个队列中的所有孩子又放回来这个队列,这样也实现了分层。
     *      而且,两个队列始终有一个队列保持为空。这样子的操作叫滚动队列。
     */
    public List<List<Integer>> levelOrder4(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        //使用两个队列来做
        Queue<TreeNode> current = new LinkedList<>();
        Queue<TreeNode> next = new LinkedList<>();

        if(root == null) {
            return result;
        } else {
            current.offer(root);
        } 

        while (!current.isEmpty()) {
            //保存某一层的元素
            ArrayList<Integer> level = new ArrayList<>();
            while (!current.isEmpty()) {
                TreeNode node = current.poll();
                level.add(node.val);
                if (node.left != null) next.add(node.left);
                if (node.right != null) next.add(node.right);
            } 
            result.add(level);
            // 交换两个队列
            Queue<TreeNode> tmp = current;
            current = next;
            next = tmp;
        } 
        return result;
    }

思路4

虽然是层序遍历,但是我们也可以用DFS来做,虽然DFS是深度优先(这是从竖直方向看),但是从水平方向看,每一层遍历结点的顺序依然是从左到右。这就是用DFS做的依据。

    /**
     * 解法4:递归法
     *      虽然是层序遍历,但是我们也可以用dfs来做,虽然dfs是深度优先(这是从竖直方向看),
     *      但是从水平方向看,每一层遍历结点的顺序依然是从左到右。这就是用dfs做的依据。
     */
    public List<List<Integer>> levelOrder1(TreeNode root) {
        List<List<Integer>> result = new ArrayList<>();
        //根节点为第一层
        traverse(root, 1, result);
        return result;
    } 

当然这题我们还需要将给定的数组转化成二叉树,使用下面的函数实现:

    /**
     * 根据给定的数组创建二叉树 
     */
    public TreeNode createBinaryTreeByArray(int[] array, int index) {
        TreeNode tn = null;
        if (index < array.length) {
            int value = array[index];
            tn = new TreeNode(value);
            tn.left = createBinaryTreeByArray(array, 2 * index + 1);
            tn.right = createBinaryTreeByArray(array, 2 * index + 2);
            return tn;
        }
        return tn;
    }

最终的测试代码如下:

    @Test
    public void test1() {
        Scanner sc = new Scanner(System.in);
        System.out.println("Enter the length of Array:");
        while(sc.hasNext()) {   
            int length = sc.nextInt();
            int[] arr = new int[length];
            for(int i = 0;i<length;i++) {
                arr[i] = sc.nextInt();
            }
            TreeNode root = createBinaryTreeByArray(arr, 0);
            System.out.println(levelOrder1(root));
            System.out.println(levelOrder2(root));
            System.out.println(levelOrder3(root));
            System.out.println(levelOrder4(root));
        }
        sc.close();
    }
}

测试结果如下:
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值