二叉树的非递归前序、中序、后序、层次、之字形遍历

335 阅读2分钟

前、中、后序遍历

题目描述

分别按照二叉树先序,中序和后序打印所有的节点。

示例1

输入

复制

{1,2,3}

返回值

复制

[[1,2,3],[2,1,3],[2,3,1]]

备注:

n \leq 10^6n≤106

解题思路

新建栈并将数根进栈

前序遍历:

  • while(栈不空):1.弹栈顶并输出 2.有右子树右子树进栈 3.有左子树左子树进栈

中序遍历:

  • 新建visited集合,记录已经从栈中弹出并打印的节点
  • while(栈不空):1. 取栈顶元素(不弹出)。2.如果栈顶元素有没被访问过的左子树就将左子树压栈,否则弹栈并输出并将右子树压栈(如果有)

后续遍历:

  • 新建visited集合,记录已经从栈中弹出并打印的节点
  • while(栈不空):1. 取栈顶元素(不弹出)。2.尝试将栈顶节点的左、右子树压栈【压栈条件,存在且没被访问过】3.尝试弹栈【弹栈条件,栈顶元素的左右子树要么不存在要么被访问过】
import java.util.*;

/**
 * @author SJ
 * @date 2021/4/4
 */
public class TraversingBinaryTree {
    public static class TreeNode {
        public int val = 0;
        public TreeNode left = null;
        public TreeNode right = null;

        public TreeNode(int val) {
            this.val = val;
        }
    }

    /**
     *
     * @param root TreeNode类 the root of binary tree
     * @return int整型二维数组
     */
    public int[][] threeOrders (TreeNode root) {

        List<Integer> listPre = preOrder(root);
        List<Integer> listIn = inOrder(root);
        List<Integer> listPost = postOrder(root);
        int size = listIn.size();

        int[][] ints = new int[3][size];
        for (int i = 0; i < size; i++) {
            ints[0][i]=listPre.get(i);
            ints[1][i]=listIn.get(i);
            ints[2][i]=listPost.get(i);
        }
        return ints;


    }

    //先根遍历
    public List<Integer> preOrder(TreeNode node){
        List<Integer> ans=new ArrayList<>();
        Deque<TreeNode> stack=new ArrayDeque<>();
        stack.push(node);

        while (!stack.isEmpty()){
            //弹出栈顶元素并输出
            TreeNode pop = stack.pop();
            ans.add(pop.val);
            //先进右子树,后进左子树,时为了到时候左子树先出
            if (pop.right!=null)
                stack.push(pop.right);
            if (pop.left!=null)
                stack.push(pop.left);

        }
        return ans;


    }
	//中根遍历
    public List<Integer> inOrder(TreeNode node){
        List<Integer> ans=new ArrayList<>();
        Deque<TreeNode> stack=new ArrayDeque<>();
        Set<TreeNode> visited=new HashSet<>();
        stack.push(node);
        while (!stack.isEmpty()){
            TreeNode peek = stack.peek();
            //如果有左子树就进左子树
            if (peek.left!=null&&!visited.contains(peek.left))
                stack.push(peek.left);
            else {//没有左子树就输出并弹出栈顶元素,并将栈顶元素的右子树压栈
                TreeNode pop = stack.pop();
                visited.add(pop);
                ans.add(pop.val);
                if (pop.right!=null)
                    stack.push(pop.right);

            }
        }
        return ans;


    }
    //后根遍历
    public List<Integer> postOrder(TreeNode node){
        List<Integer> ans=new ArrayList<>();
        Deque<TreeNode> stack=new ArrayDeque<>();
        Set<TreeNode> visited=new HashSet<>();
        stack.push(node);

        while (!stack.isEmpty()){
            //每次取栈顶元素,尝试将右子树和左子树压入栈
            TreeNode peek = stack.peek();
            TreeNode right = peek.right;
            TreeNode left = peek.left;
            if (right!=null&&!visited.contains(right))
                stack.push(right);
            if (left!=null&&!visited.contains(left))
                stack.push(left);

            //一个节点能输出,当且仅当这个节点的子树都无法被输出
            if ((right==null||visited.contains(right))&&(left==null||visited.contains(left))){
                TreeNode pop = stack.pop();
                ans.add(pop.val);
                visited.add(pop);
            }

        }
        return ans;
    }

    public static void main(String[] args) {
        TreeNode n1 = new TreeNode(1);
        TreeNode n2 = new TreeNode(2);
        TreeNode n3 = new TreeNode(3);
        n1.left=n2;
        n1.right=n3;
        TraversingBinaryTree traversingBinaryTree = new TraversingBinaryTree();
        traversingBinaryTree.threeOrders(n1);
    }
}

层次遍历

题目描述

给定一个二叉树,返回该二叉树层序遍历的结果,(从左到右,一层一层地遍历) 例如: 给定的二叉树是{3,9,20,#,#,15,7}, img 该二叉树层序遍历的结果是 [ [3], [9,20], [15,7] ]

解题思路

其实普通的层次遍历很简单,一个队列就可以完成。这个有点特殊,需要每层输出一个结果数组,此时就要区分这个节点时哪一层的了。

新建两个队列:队列1和队列2

  • 1.将根节点加入队列1
  • 2.遍历队列1,同时将遍历到节点的左右子树加入队列2
  • 3.遍历完之后,队列1已空,将队列1和队列2交换名称
  • 重复2,3 直至队列1空
import java.util.*;

/**
 * @author SJ
 * @date 2021/4/4
 */
public class LevelOrder {
    public static class TreeNode {
        public int val = 0;
        public TreeNode left = null;
        public TreeNode right = null;

        public TreeNode(int val) {
            this.val = val;
        }
    }

    /**
     * @param root TreeNode类
     * @return int整型ArrayList<ArrayList <>>
     */
    public ArrayList<ArrayList<Integer>> levelOrder(TreeNode root) {
        ArrayList<ArrayList<Integer>> ans = new ArrayList<>();
        if (root == null)
            return ans;

        Deque<TreeNode> queue1 = new ArrayDeque<>();
        Deque<TreeNode> queue2 = new ArrayDeque<>();
        queue1.add(root);

        int layer = 0;
        //两个队列来回倒,每次队列里装一层,另一个队列里装这一层的子节点
        while (!queue1.isEmpty()) {
            ans.add(new ArrayList<>());

            while (!queue1.isEmpty()) {

                TreeNode poll = queue1.poll();              
                ans.get(layer).add(poll.val);              
                if (poll.left != null)
                    queue2.add(poll.left);
                if (poll.right != null)
                    queue2.add(poll.right);


            }
            Deque<TreeNode> temp;
            temp = queue1;
            queue1 = queue2;
            queue2 = temp;
            layer++;
        }
        return ans;

    }

    public static void main(String[] args) {
        TreeNode n1 = new TreeNode(1);
        TreeNode n2 = new TreeNode(2);
        TreeNode n3 = new TreeNode(3);

        n1.left = n2;
        n1.right = n3;

        LevelOrder levelOrder = new LevelOrder();
        ArrayList<ArrayList<Integer>> arrayLists = levelOrder.levelOrder(n1);
        for (ArrayList<Integer> arrayList : arrayLists) {
            System.out.println(arrayList.toString());
        }

    }
}

之字形遍历

题目描述

给定一个二叉树,返回该二叉树的之字形层序遍历,(第一层从左向右,下一层从右向左,一直这样交替) 例如: 给定的二叉树是{3,9,20,#,#,15,7}, img 该二叉树之字形层序遍历的结果是

[

[3],

[20,9],

[15,7]

]

解题思路

之字形遍历,层次遍历结果集里奇数层倒着插就行,哪有那么复杂。

		if (layer%2 == 0)
                   ans.get(layer).add(poll.val);
                else
                    ans.get(layer).add(0, poll.val);