二叉树的前序-中序-后序遍历

在牛客网刷到了二叉树的遍历,二叉树的遍历分为前序遍历,前序遍历也有先序遍历之称,还有中序遍历,以及后序遍历,这么多种遍历,遍历的方式不一样而已,前序遍历是先遍历根然后左节点然后是右节点,就是根左右,中序遍历的话是左根右,后序遍历是左右根,

1种:一般遍历采取递归方式,比如根左右,在调用左节点一直递归直到找到左边结束,到某个节点分叉口时再继续遍历邻节点也是同样方式一直递归,直到所有节点递归完,

2种:除了递归以外也可以通过栈(先进后出,后进的先出)方式遍历树,先把树根节点存储到栈里,然后开始取出树根存储到集合里,继续往栈里存放先放右节点,再放左节点,这样继续循环取就先取左边的数据了。

准备工作,我们先来定义二叉树的节点TreeNode

public class TwoTreeBeforeIterable {

   public static class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;

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

1.前序遍历

咱们先实现个用栈思想来进行前序遍历操作

    // 利用栈思想,先进后出
    public static int[] preorderTraversal1(TreeNode root) {
        LinkedList<Integer> list = new LinkedList<>();
        if (root == null) {
            return new int[0];
        }
        // 先把树节点存放在栈种
        ArrayDeque<TreeNode> que = new ArrayDeque<>();
        que.push(root);
        while (!que.isEmpty()) {
            // 取出树节点
            TreeNode node = que.pop();
            // 存储节点
            list.add(node.val);

            //根左右,由于栈是先进后出,所以要让左节点后入栈,这样才能先弹出来
            if (node.right != null) {
                // 先往栈里存放右节点
                que.push(node.right);
            }
            if (node.left != null) {
                // 再往栈里存放左节点
                que.push(node.left);
            }

        }
        return list.stream().mapToInt(Integer::intValue).toArray();
    }

                                        5

                              4                6

                         1       2 

测试:

public static void main(String[] args) {

        // 生成树结构开始
        TreeNode treeNode = new TreeNode(5);
        TreeNode treeLeftNode = new TreeNode(4);
        TreeNode treeRightNode = new TreeNode(6);


        TreeNode treeLeftLeftNode = new TreeNode(1);
        TreeNode treeRightRightNode = new TreeNode(2);

        treeNode.left = treeLeftNode;
        treeNode.right = treeRightNode;

        treeLeftNode.left = treeLeftLeftNode;
        treeLeftNode.right = treeRightRightNode;

        treeRightNode.right = null;
        treeRightNode.left = null;
        // 生成树结构结束

        int[] s = TwoTreeBeforeIterable.preorderTraversal1(treeNode);
        System.out.println(Arrays.toString(s));
}

结果:

[5, 4, 1, 2, 6]

递归实现下先序遍历,递归这种方式也叫深度优先遍历,

深度优先遍历先找到当前节点,然后沿着某一节点一直走到底,再通过节点返回走下一节点邻节点,

根左右,所以再存list时先存储root.val,然后再递归左边,左边深度遍历完毕,再递归节点右部,直到全部遍历完毕

public static int[] preorderTraversal2(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        dfs(list, root);
        return list.stream().mapToInt(Integer::intValue).toArray();
 }
public static void dfs(List<Integer> list, TreeNode root) {
        if (root != null) {
            list.add(root.val);
            dfs(list, root.left);
            dfs(list, root.right);
        }
    }

 用刚才的示例测试递归方式的,结果是一样的

中序遍历

其实按照递归方式,我们很容易的就能实现二叉树的中序遍历,在递归时,先递归左部,再存储到list值,再递归右部即可。


    // 二叉树中序遍历--------------------------------------------------------开始
    // 左根右
    public static int[] preorderTraversal3Mid(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        dfsMid(list, root);
        return list.stream().mapToInt(Integer::intValue).toArray();
    }

    public static void dfsMid(List<Integer> list, TreeNode root) {
        if (root != null) {
            dfsMid(list, root.left);
            list.add(root.val);
            dfsMid(list, root.right);
        }
    }


    // 二叉树中序遍历--------------------------------------------------------结束

                                       5

                              4                6

                         1       2 

结果:[1, 4, 2, 5, 6]

后序遍历

后序遍历是左右根,前序遍历和中序遍历,你都知道了,那后序遍历就不用多说了

 // 二叉树后序遍历--------------------------------------------------------开始
    // 左右根遍历
    public static int[] preorderTraversal3Back(TreeNode root) {
        ArrayList<Integer> que = new ArrayList<>();
        dfsBack(que, root);
        return que.stream().mapToInt(Integer::intValue).toArray();
    }

    public static void dfsBack(ArrayList<Integer> que, TreeNode root) {
        if (root != null) {
            dfsBack(que, root.left);
            dfsBack(que, root.right);
            que.add(root.val);
        }
    }

    /*
    *
    *
    *                          1
    *                   2                3
    *            4          5      6         7
    * 后序递归遍历分析:
    * 代码逻辑是先找左边递归
    * 1.这样进来就先找到1的left,再次进入递归得到left2,再次进入递归得到left4,再此进入左节点为空,得到右节点为空
    * 此时把4存储起来que.add(root.val);
    * 2.4的上一个节点2递归到右边找到5,找到5的节点的左右节点,发现没有把5存储起来que.add(root.val);
    * 3.5的上一个节点2(左右都递归完毕)递归完毕,把2存储起来que.add(root.val);
    * 4.root就变为1节点,root此时的左边节点全部找到,开始处理右部节点3,找3的左部节点为6,再找6的左节点发现没有,递归结束,再找6的右节点也没有
    *   开始存储6 que.add(root.val);
    * 5.此时root节点变为3,找3的右节点为7,找7的左节点为空,找7的右节点为空,此时存储7que.add(root.val);
    * 6.此时3的左右节点全部遍历完毕,直接存储3 que.add(root.val);
    * 7.此时1的左右节点全部遍历完毕,直接存储1 que.add(root.val);
    * 最终按照左右根方式输出为:[4, 5, 2, 6, 7, 3, 1]
    *     **/

    // 二叉树后序遍历--------------------------------------------------------结束

 测试一下

                                           1

                            2                          3

                 4                   5          6              7

        TreeNode treeNode = new TreeNode(1);
        TreeNode treeLeftNode = new TreeNode(2);
        TreeNode treeRightNode = new TreeNode(3);


        treeNode.left = treeLeftNode;
        treeNode.right = treeRightNode;

        TreeNode treeLeftLeftNode = new TreeNode(4);
        TreeNode treeLeftRightNode = new TreeNode(5);
        treeLeftNode.left = treeLeftLeftNode;
        treeLeftNode.right = treeLeftRightNode;

        TreeNode treerightLeftNode = new TreeNode(6);
        TreeNode treeRightRightNode = new TreeNode(7);
        treeRightNode.left = treerightLeftNode;
        treeRightNode.right = treeRightRightNode;

        int[] s = TwoTreeBeforeIterable.preorderTraversal3Back(treeNode);
        System.out.println(Arrays.toString(s));

结果:[4, 5, 2, 6, 7, 3, 1]

时间复杂度空间复杂度都为O(n)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值