规划化二叉树的遍历--最简单的非递归记忆

本文介绍了一种使用栈实现二叉树前序、中序和后序非递归遍历的方法,特别是提供了一种简洁的后序遍历算法,通过调整前序遍历的顺序并反转结果,使得后序遍历更易于理解和实现。
/*
*   二叉树的非递归遍历,前序中序还是挺简单的,可是后序遍历就需要一个pre来记录前一个指针了,我老是忘记要怎么写后序非递归。
*    今天参考了https://blog.youkuaiyun.com/u012975705/article/details/80258664的博客,自己就规划化三种非递归遍历,写完之后
*   就觉得后序遍历不用pre,变得超级简单了,而且三种遍历很相似,完全可以比较记忆,还是自己的想法不够好。代码能跑通,也可以和上一篇
*   结合起来看待。
*
*
*
*/
import java.util.*;


//结点定义
class TreeNode {
    int data;
    TreeNode left, right;


    public TreeNode(int data) {
        this.data = data;
        this.left = null;
        this.right = null;
    }
}


//测试
public class Solution {
    public static void main(String args[]) {


        int preOrder[] = new int[]{10, 3, 1, 2, 9, 4, 8, 5, 7, 6};
        int inOrder[] = new int[]{1, 3, 2, 10, 4, 9, 5, 8, 6, 7};
        //调用建树的函数
        Solution s = new Solution();
        TreeNode root = s.buildTree(preOrder, 0, preOrder.length - 1, inOrder, 0, inOrder.length - 1);
        s.preTravel(root);
        s.inTravel(root);
        s.postTravel(root);


    }




    //前序非递归,这个是最简单的二叉树非递归遍历 顺序是DLR
    public void preTravel(TreeNode root) {
        if (root == null)
            return;
        //保存结果用
        ArrayList<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
       while(!stack.empty()||cur!=null){
           //左孩子一直入栈,并且一个左孩子的后继节点还是左孩子,所以顺序地保存为结果
           while(cur!=null){
               stack.push(cur);
               res.add(cur.data);
               cur=cur.left;
           }
           //弹出最左边的孩子
           cur=stack.pop();
           cur=cur.right;             //cur必要时为空,不然死循环
       }




        System.out.println("前序:" + res.toString());
    }




    //中序非递归,最常用到
    public void inTravel(TreeNode root) {
        if (root == null)
            return;
        //保存结果
        ArrayList<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur=root;
        //目标是得到LDR,所以先找到最左孩子
        while(!stack.empty()||cur!=null){
            //找到最左孩子
            while(cur!=null){
                stack.push(cur);
                cur=cur.left;
            }
            cur =stack.pop();
            res.add(cur.data);
            cur=cur.right;




        }
      System.out.println("中序:"+res.toString());
    }




    //后序非递归,最难,在之前的一篇博客写过设置pre的方法,在这里更新一种方法,根据前序DLR,我们只要稍作改变就可以得到DRL是不?
    //再把DRL翻转一下,就得到了后序LRD了,这种方法可以和前序比较记忆,所以强烈推荐这么做,这样一来其实后序就有两种遍历方法了
    public void postTravel(TreeNode root) {
        if (root == null)
            return;
        //保存结果
        ArrayList<Integer> res = new ArrayList<>();
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur=root;
        //目标是得到DRL,最后结果再翻转为LRD
           while(!stack.empty()||cur!=null){
            //仿照前序遍历,一个孩子的后继节点为他的右孩子,不断找到最右孩子,并且记录路径和结果
               while(cur!=null){
                   stack.push(cur);
                   res.add(cur.data);
                   cur=cur.right;
               }
               //弹出最右界结点
               cur=stack.pop();                //配合前序写这个简单绝配!!!!妈妈再也不用担心写不来后序遍历了
               cur=cur.left;
          }
          //一定记得翻转
          Collections.reverse(res);
   System.out.println("后序:"+res.toString());
    }




    //根据前序和中序建立一颗二叉树
    public TreeNode buildTree(int preOrder[], int preStart, int preEnd, int inOrder[], int inStart, int inEnd) {
        //根节点
        if (preStart > preEnd || inStart > inEnd)
            return null;
        TreeNode root = new TreeNode(preOrder[preStart]);
        //空树,递归出口
        if (preStart == preEnd || inStart == inEnd)
            return root;


        //找到根节点在中序中的位置,以便划分成两部分
        int loc = locateRoot(preOrder[preStart], inOrder);
        root.left = buildTree(preOrder, preStart + 1, loc - inStart + preStart, inOrder, inStart, loc - 1);
        root.right = buildTree(preOrder, loc - inStart + preStart + 1, preEnd, inOrder, loc + 1, inEnd);
        return root;
    }


    //找到结点在中序遍历的位置,帮助建树
    public int locateRoot(int key, int inOrder[]) {
        for (int i = 0; i < inOrder.length; i++)
            if (inOrder[i] == key)
                return i;
        return -1;
    }



}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值