二叉树遍历的非递归实现

首先确定一点,不管是先序、中序还是后序,二叉树遍历都是先遍历左子树,然后逐层回溯遍历右子树,所以三种非递归方式都需要借助于栈的数据结构。

1.先序遍历思想及实现

  • 扫描并且访问根节点、及其所有左节点并将它们依次入栈
  • 栈顶出栈,记位p,注意p已经访问过。
  • 扫描并访问p的右节点、及该右节点的所有左节点并依次入栈

结束条件“栈不为空”或“p!=null”,分别对应遍历左子树时和遍历右子树时的两种情况

public void notRecruisePreOrder(BtNode p){
        Stack<BtNode> s=new Stack<BtNode>();
        while(!s.isEmpty() || p!=null){
            if(p==null){
                p=s.pop();
                p=p.getRight();
            }
            else{
                System.out.println(p.getValue());
                s.push(p);
                p=p.getLeft();
            }
        }
    }

 

2.中序遍历思想与先序遍历基本一致,区别在于访问节点的时机为p出栈时访问,这是因为先序和中序遍历的轨迹是一样的。

3.后序遍历思想及实现

  后序遍历情况有一些不同,因为后序遍历一个节点需要先遍历其左子树,再遍历其右子树,最后遍历该节点。所以隐含的逻辑是:入栈时,只需将该节点的所有左节点依次入栈,并移动p至当前栈顶的叶子节点;出栈时,需要右子树已经访问过,否则将右子树同样入栈。

  为了表示右节点的访问状态,我们使用lastNode记录上一个访问节点,如果它等于当前节点的右孩子,那么右子树已经访问过。

public void notRecruisePostOrder(BtNode r){
        
        if(r==null) return;
        
        Stack<BtNode> s=new Stack<BtNode>();
        
        BtNode p=r, lastNode=null;//用lastNode记录上一次访问的节点
        //将当前节点的所有左节点依次入栈,并移动p至当前栈顶的叶子节点
        while(p!=null){
            s.push(p);
            p=p.getLeft();
        }
        
        while(!s.isEmpty()){
            p=s.peek();
            //访问节点的时机:或者其右孩子已经被访问过,或者该元素没有右孩子。
            if(p.getRight()==null || lastNode==p.getRight()){
                System.out.println(s.pop().getValue());
                lastNode=p;
            }
            else
            {
                //将右子树按同样道理入栈,并且移动当前节点
                p=p.getRight();
                while(p!=null){
                    s.push(p);
                    p=p.getLeft();
                }
            }
        }
    }

 

posted @ 2016-04-21 20:25  来自外星的你  阅读(137)  评论(0)    收藏  举报