数据结构------二叉树的遍历(递归与非递归方法)

在这里总结一下二叉树的几种遍历各自的递归与非递归写法。


目录

0. 树节点的定义:

1. 先序遍历:

1.1 递归实现:

1.2 非递归实现:

 2. 中序遍历:

2.1 递归方法:

2.2 非递归方法:

3. 后序遍历:

3.1 递归方法:

3.2 非递归方法:

 4. 层次遍历:

4.1 层次遍历的遍历过程:


如果对这几种遍历还不了解的,可以先了解一下。对于一棵如下的二叉树:

其先序遍历为:(根左右)ABDECFG

    中序遍历为:(左根右)DBEAFCG

    后序遍历为:(左右根)DEBFGCA

    层次遍历为:ABCDEFG


0. 树节点的定义:

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

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

 

1. 先序遍历:

(助记顺序:根左右

1.1 递归实现:

    基本思路就是每到一个节点先输出其自己的值(),然后再遍历其的左节点(),直到没有左节点了,开始遍历右节点(),直到叶子节点然后返回,每一层都进行类似步骤。

    public static void preOrderRec(TreeNode pRoot) {
        if (pRoot != null) {
            System.out.print(pRoot.val + " ");
            preOrderRec(pRoot.left);
            preOrderRec(pRoot.right);
        }
    }

1.2 非递归实现:

    非递归方法的基本思路就是利用栈,但可以有多种不同实现方式,这里我先输出当前节点(),然后将所以其左节点压到栈中,方便后面出栈来处理其的右节点,然后把当前的对象指针指到其左节点(),即代码中的 pRoot = pRoot.left ,然后 while 判断pRoot 不为空,所以继续将其输出,然后移到其左节点,直到没有左节点了,通过出栈开始处理右节点()。

    import java.util.Stack;    

    public void preOreder(TreeNode pRoot) {
        //通过栈来实现先序遍历的非递归实现
        Stack<TreeNode> stack = new Stack<>();
        
        while (true) {
            //输出当前节点,并将当前节点压栈,然后寻找其是否还有左节点
            while (pRoot != null) {
                System.out.print(pRoot.val + " ");
                stack.push(pRoot);
                pRoot = pRoot.left;
            }
            
            //唯一出口
            if (stack.empty()) break;

            //弹出栈顶节点,可以理解为对其右子树再进行先序遍历
            pRoot = stack.pop();
            pRoot = pRoot.right;
        }
    }

 

 2. 中序遍历:

(助记顺序:左根右

2.1 递归方法:

    递归的方法和先序很像,只是把输出移到了中间位置,这样就会让其先遍历完左子树,到达最左叶子节点后开始输出(),因为是叶子节点,所以返回上一层输出(),再遍历当层的右子树()。

    public void inOrderRec(TreeNode pRoot) {
        if (pRoot != null) {
            inOrderRec(pRoot.left);
            System.out.print(pRoot.val + " ");
            inOrderRec(pRoot.right);
        }
    }

2.2 非递归方法:

    这里非递归的方法也和先序很相似,都是改变输出的位置,只要理解了就很容易记忆。因为是先压所有的左节点直到叶子节点,所以保证它已经没有左节点,所以可以输出,然后再判断其是否有右子树。

    import java.util.Stack;    

    public void inOrder(TreeNode pRoot) {
        //通过栈来实现中序遍历的非递归实现
        Stack<TreeNode> stack = new Stack<>();

        //输出当前节点,并将当前节点压栈,然后寻找其是否还有左节点
        while (true) {
            while (pRoot != null) {
                //只是压入,因为输入顺序是“左根右”,所以还不能输出
                stack.push(pRoot);
                pRoot = pRoot.left;
            }

            //唯一出口
            if (stack.empty()) return;

            pRoot = stack.pop();
            //由于上面将左节点压入,所以这里输出就是先输出左节点
            System.out.print(pRoot.val + " ");
            pRoot = pRoot.right;

        }
    }

 

3. 后序遍历:

(助记顺序:左右根

3.1 递归方法:

    三种递归遍历方法其实都是一个样子,只是改变了输出的位置。

    public void postOrderRec(TreeNode pRoot) {
        if (pRoot != null) {
            postOrderRec(pRoot.left);
            postOrderRec(pRoot.right);
            System.out.print(pRoot.val + " ");
        }
    }

3.2 非递归方法:

    这里我的非递归方法是参考这里的博客的,我们可以对先序遍历进行修改,修改成顺序为根右左的遍历顺序,然后只要将其倒过来输出就是我们所要的后序遍历了。

    import java.util.Stack;   
 
    public static void postOreder(TreeNode pRoot) {
        //用来进行根右左遍历的栈
        Stack<TreeNode> stack = new Stack<>();
        //保存逆序输出结果的栈
        Stack<TreeNode> resStack = new Stack<>();

        while (true) {
            //改为先压入右子树
            while (pRoot != null) {
                stack.push(pRoot);
                resStack.push(pRoot);
                pRoot = pRoot.right;
            }

            if (stack.empty()) break;

            pRoot = stack.pop();
            pRoot = pRoot.left;
        }

        //将结果逆序输出,即为后序遍历左右根的顺序
        while (!resStack.empty()) {
            System.out.print(resStack.pop().val + " ");
        }
    }

 

 4. 层次遍历:

    与树的前中后序遍历不同的是,层次遍历用到的是BFS的思想,而前中后序遍历是的DFS思想。一般的DFS都可用递归或者栈来实现,而对于BFS则需要使用队列来实现。

4.1 层次遍历的遍历过程:

  1. 对于不为空的节点,就将该节点进队
  2. 从队列中出列一个节点,如果它有左节点,则将左节点进队;如果有右节点,就将右节点进队
  3. 如此操作直到队空为止

实现代码如下:

    import java.util.Queue;  

    public static void levelOrder(TreeNode pRoot) {

        if (pRoot == null) return;

        //申请一个队列
        Queue<TreeNode> queue = new LinkedList<>();

        //首节点入队
        queue.offer(pRoot);

        while (!queue.isEmpty()) {

            //出队一个节点
            pRoot = queue.poll();
            System.out.print(pRoot.val + " ");

            //如果左右节点存在,则将其左右节点入队
            if (null != pRoot.left)
                queue.offer(pRoot.left);
            if (null != pRoot.right) {
                queue.offer(pRoot.right);
            }
        }
    }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值