BST的后续遍历

真没想到一个非递归中序遍历也能搞死我。我是有多弱啊,更别说后续遍历了。

看看人家的代码,那真是八仙过海,各显神通,弱爆了就是我啊就是我

方法1: 参考http://blog.csdn.net/wzy_1988/article/details/17072953

ArrayList<Integer> s1(TreeNode root){
        ArrayList<Integer> list=new ArrayList<Integer>();
        Stack<TreeNode> st=new Stack<TreeNode>();
        TreeNode pre=null;
        while(st.size()>0||root!=null){
            if(root!=null){
                st.push(root);
                root=root.left;
            }else{
                root=st.pop();
                if(root.right==null||root.right==pre){
                    list.add(root.val);
                    pre=root;
                    root=null;
                }else{
                    st.push(root);
                    root=root.right;
                }
            }
        }
        return list;
    }

先看一下大神1的方法,和中序前序遍历一样,首先遍历最左子树,这个没问题,一直走while里的if模块。

一直走到左子树没有了,这时候pop一下取出来最后一个点。这时候,

如果是中序遍历就可以直接加上这个点然后走右边了,

如果是先序遍历更简单,在if里就add到list里就行,这里也是直接走右孩子就可以。

 

    但是这是后序遍历,后序遍历里中间节点最后查看,所以这里要判断一下,如果没有右孩子或者右边孩子已经遍历过(pre来存上次遍历的点),那么就可以加入这个点了。也就是两个else中间的代码,注意这里有一句root=null值得分析一下。其实这里还有一个隐式约定:root==null既是循环增加左子树完毕的判定条件,也是后面遍历过程中要求pop新节点的请求条件。

     然后就简单了,如果不能加入这个点,对不起还得把你塞回去,然后下一次遍历root.right就ok。 


如果顺着先序和中序写下来多半想到的是这种方法。


方法2: 参考http://www.cnblogs.com/TenosDoIt/p/3416835.html

 ArrayList<Integer> s2(TreeNode root){
        ArrayList<Integer> list=new ArrayList<Integer>();
        Stack<TreeNode> st=new Stack<TreeNode>();
        if(root==null)
            return list;
        st.push(root);
        TreeNode pre=null;
        while(st.size()>0){
            root=st.peek();
            if((root.left==null&&root.right==null)||(pre!=null&&(pre==root.left||pre==root.right))){
                list.add(root.val);
                pre=root;
                st.pop();
            }else{
                if(root.right!=null)
                    st.push(root.right);
                if(root.left!=null)
                    st.push(root.left);
            }
        }
        return list;
     }

再看看大神2的方法,这两种方法复杂度肯定是完全一致的,但思路却完全不同。

连循环加入左节点的步骤都省下了,真是太猛了。

第一步,root入栈。

第二步,peek一个节点。然后分两种情况判断:

   情况1: 如果是叶节点,或者刚处理了它的左节点或者右节点(注意!这里一定要加上左节点,不然必错,想想为啥?),那么就在list上假如这个结果,pop了这个节点,pre记录下处理了这个节点。

   情况2: 非情况1的情况,即这点或者不是叶节点,且,这个点的左右子节点都没有处理,那么处理这个点。处理方式:st.push(root.right); st.push(root.left);


   咱们走一遍整个逻辑,假设树={1,2,3,4,5,6,7}先走根节点,不是叶节点且子节点都没处理,所以加入3,2。循环走完第一遍,peek=2,假如5,4,循环第二遍走完。

第三遍: peek=4,叶节点,加入4为第一个值,pre=4;

第四遍:peek=5 加入结果 4,5  pre=5

5: peek=2,pre=5,为右孩子,4,5,2

6:peek=3, add 7,6, stack=1,3,7,6 pre=5

peek 6 peek 7 peek 3 peek 1 结束。


怎么看怎么那个pre=root.left判不到对吧,再来个树1,2,3,4,#,#,#, 再走一遍就明白了,走4之后,没有右孩子,所以走2,你没有pre=root.left 不是找死么





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值