1. 程式人生 > >把二叉樹列印成多行

把二叉樹列印成多行

題目

從上到下按層列印二叉樹,同一層結點從左至右輸出。每一層輸出一行。

思路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錯誤,因為result裡儲存的是arr指向的這個ArrayList物件,這裡把arr清空了意味著 * 把這個物件裡的內容清空了,所以result裡就為空了! * 應該將arr再重新指向一個新的ArrayList物件即可! */ 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();
    }
}

測試結果如下: 這裡寫圖片描述