二叉树的先序、中序、后序遍历(递归实现+非递归实现)

树的遍历顺序大体分为三种:先序遍历(先根遍历),中序遍历(中根遍历),后序遍历(后根遍历)。


二叉树的先序、中序、后序遍历是什么意思?

先序:每一棵子树的打印的顺序都是:头--左--右

中序:每一棵子树的打印的顺序都是:左--头--右

后序:每一棵子树的打印的顺序都是:左--右--头


一、递归实现(比较简单):

先序遍历:

    //先序打印二叉树所有节点
    public static void prePrint(Node head) {
        if (head == null) {
            return;
        }
        System.out.println(head);
        prePrint(head.left);
        prePrint(head.right);
    }

中序遍历:

    //中序打印二叉树所有节点
    public static void inPrint(Node head) {
        if (head == null) {
            return;
        }
        inPrint(head.left);
        System.out.println(head);
        inPrint(head.right);
    }

后序遍历:

    //后序打印二叉树所有节点
    public static void posPrint(Node head) {
        if (head == null) {
            return;
        }
        posPrint(head.left);
        posPrint(head.right);
        System.out.println(head);
    }

重点理解递归序

递归序:先序中序后序的实现就是依靠递归序,先序(第一次打印)中序(第二次打印)后序(第三次打印)------>递归序任意节点的数据遍历都到三次

二、非递归实现(稍微难理解)

1.用栈实现先序遍历:

实现步骤:

        1.定义一个currentNode当作遍历的辅助节点,并将头节点添加进栈

        2.当栈不为空时,弹出节点并打印,然后在有子节点的情况下:先添加右节点进栈,再添加左节点进栈,因为栈遵循先进后出原则,为完成先序遍历(头--左--右)的顺序,需要先添加右边的节点再添加左边的节点

        3.直到没有子节点往栈里面添加,并且栈里面的节点全部取出时,退出循环

    public static void pre(Node head) {
        if (head != null) {
            Stack<Node> stack = new Stack<>();
            stack.add(head);
            Node currentNode = null;
            while (!stack.isEmpty()) {
                currentNode = stack.pop();
                System.out.println(currentNode);
                if (currentNode.right != null) {//一定要先把右节点压入栈中,因为从栈里面弹出的顺序是反的
                    stack.push(currentNode.right);
                }
                if (currentNode.left != null) {
                    stack.push(currentNode.left);
                }
            }
        }
    }

2.用栈实现中序遍历:

实现思路:

        把二叉树看作有限个关于left指针的单链表(只是这么认为,二非真是单链表,因为二叉树的节点有两条指针)。eg:链表一:head-->head.left-->head.left.left-->直到遇到null;链表二:head.right-->head.right.left-->head.right.left.left-->直到遇到null……因为中序遍历要求顺序是左-->头-->右,将left指针的链表节点存入栈,再弹出节点即可得到(需要注意:弹出一个节点,currentNode需要变成右子节点)

实现步骤:

        1.定义一个栈用于存放节点

        2.currentNode不为空的时候(currentNode是一直往left指针遍历,直到遇到null),将currentNode添加进栈,并且currentNode移动到左子节点,再次判断是否为空,是否需要添加进栈

        3.如果碰到currentNode为null了,那么就从栈里面取出一个节点并打印,再把currentNode指向右子节点,再次判断是否为空,是否需要添加进栈

        4.直到栈里面的节点被弹出完,currentNode遍历完二叉树的所有子节点遇到null,退出循环

    public static void in(Node currentNode) {
        if (currentNode != null) {
            Stack<Node> stack = new Stack<>();
            while (!stack.isEmpty() || currentNode != null) {
                if (currentNode != null) {
                    stack.push(currentNode);
                    currentNode = currentNode.left;
                } else {
                    currentNode = stack.pop();
                    System.out.println(currentNode);
                    currentNode = currentNode.right;
                }
            }
        }
    }

3.用栈实现后序遍历

思路:

        用栈实现后序遍历类似于先序遍历,不同之处两点:1.往栈里面添加数据的时候先添加左节点,在添加右节点(这样弹出来的顺序就会是"头-->右-->左");2.完成之后,再添加依次进栈,再取出节点,这样弹出节点的顺序就是“左-->右-->头”,满足后序遍历

实现步骤如用栈实现先序遍历,两点区别在思路中阐述清楚,直接上代码

    public static void pos(Node head) {
        if (head != null) {
            Stack<Node> stack = new Stack<>();
            Stack<Node> posStack = new Stack<>();
            stack.add(head);
            Node currentNode = null;
            while (!stack.isEmpty()) {
                currentNode = stack.pop();
                posStack.push(currentNode);
                if (currentNode.left != null) {
                    stack.push(currentNode.left);
                }
                if (currentNode.right != null) {
                    stack.push(currentNode.right);
                }
            }
            while (!posStack.isEmpty()) {
                System.out.println(posStack.pop());
            }
        }
    }

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值