二叉树的遍历-非递归方式

分别用非递归的方式实现二叉树的先序遍历、中序遍历和后续遍历


非递归方式实现二叉树的先序遍历。

过程:

1.申请一个新的栈,记为stack, 然后将二叉树的头结点head压入stack中。

2.从stack中弹出栈顶结点,记为cur,然后打印cur结点的值,再将结点cur的右孩子(不为空的话)先压入stack中,最后将cur的左孩子(不为空的话)压入stack中。

3.不断重复步骤2,直到stack为空,全部过程结束。

实现代码如下:

public void preOrderUnRecur(Node head){
        System.out.print("pre-order: ");
        if(head != null){
            Stack<Node> stack = new Stack<Node>();
            stack.add(head);
            while(!stack.isEmpty()){
                head = stack.pop();
                System.out.print(head.value + " ");
                if(head.right != null){
                    stack.push(head.right);
                }
                if(head.left != null){
                    stack.push(head.left);
                }
            }
        }
        System.out.println();
}


非递归方式实现二叉树的中序遍历

过程:

1.申请一个新的栈,记为stack。初始时,令变量cur = head;

2.先把cur结点压入栈中,对以cur结点为头的整棵子树来说,依次把左边界压入栈中,即不停地令cur=cur.left,然后重复步骤2。

3.不断重复步骤2,直到发现cur为空,此时从stack中弹出一个结点,记为node。打印node的值,并且让cur = node.right,然后继续重复步骤2。

4.当stack为空且cur为空时,整个过程停止。

实现代码如下:

public void inOrderUnRecur(Node head){
        System.out.print("in-order:");
        if(head != null){
            Stack<Node> stack = new Stack<>();
            while(!stack.isEmpty() || head != null){
                if(head != null){
                    stack.push(head);
                    head = head.left;
                }else{
                    head = stack.pop();
                    System.out.println(head.value);
                    head = head.right;
                }
            }
        }
        System.out.println();
}


非递归方式实现二叉树的后续遍历-实现方式一:使用两个栈实现

过程:

1.申请一个栈,记为s1,然后将树的头结点head压入s1中

2.从s1中弹出的结点记为cur,然后依次将cur的左孩子和右孩子压入s1中

3.在整个过程中,每一个从s1中弹出的结点都放进s2里。

4.不断重复步骤2和步骤3,直到s1为空,过程停止。

5.从s2中依次弹出结点并打印,打印的顺序就是后续遍历的顺序。

实现代码如下:

public void posOrderUnRecur(Node head){

        System.out.print("pos-order (two stack):");
        if(head != null){
            Stack<Node> s1 = new Stack<>();
            Stack<Node> s2 = new Stack<>();
            s1.push(head);
            while(!s1.isEmpty()){
                head = s1.pop();
                s2.push(head);
                if(head.left != null){
                    s1.push(head.left);
                }
                if(head.right != null){
                    s1.push(head.right);
                }
            }
            while(!s2.isEmpty()){
                System.out.print(s2.pop().value + " ");
            }
        }
        System.out.println();
}

备注: 每棵子树的头结点都最先从s1中弹出,然后把该结点的孩子结点按照先左再右的顺序压入s1,那么从s1弹出的顺序就是从右再左,所以从s1中弹出的顺序就是中、右、左。然后,s2重新收集的过程就是s1的弹出顺序逆序,也就是左、右、中。所以s2从栈顶到栈底的顺序就变成了左、右、中,打印出的结果就是后序遍历的结果。


非递归方式实现二叉树的后续遍历-实现方式二:使用一个栈实现

过程:

1.申请一个栈,记为stack,将头结点压入stack,同时设置两个变量h和c。在整个流程中,h代表最近一次弹出并打印的结点,c代表stack的栈顶结点。初始时h为头结点,c为null。

2.每次令c等于当前Stack的栈顶结点,但是不从stack中弹出,此时分以下三种情况:

(1)如果c的左孩子不为null,且h不等于c的左孩子,也不等于c的右孩子,则把c的左孩子压入stack中。解释一下这么做的原因,首先h的意义是最近一次弹出并打印的结点,所以如果h等于c的左孩子或者右孩子,说明c的左子树与右子树打印完毕,此时不应该再将c的左孩子放入stack中。否则,说明左子树还没处理过,那么此时将c的左孩子压入stack中。

(2)如果条件1不成立,并且c的右孩子不为null,h不等于c的右孩子,则把c的右孩子压入stack中。含义是如果h等于c的右孩子,说明c的右子树已经打印完毕,此时不应该再将c的右孩子放入stack中。否则,说明右子树还没被处理过,此时将c的右孩子压入stack中。

(3)如果条件(1)和条件(2)都不成立,说明c的左子树和右子树都已经打印完毕,那么从stack中弹出c并打印,然后令h = c。

3.一直重复步骤2,直到stack为空,过程停止。

实现代码如下:

public void posOrderUnRecur2(Node h){
        System.out.print("pos-order (one stack) :");
        if(h != null){
            Stack<Node> stack = new Stack<>();
            stack.push(h);
            Node c = null;
            while(!stack.isEmpty()){
                c = stack.peek();
                if(c.left != null && h != c.left && h != c.right){
                    stack.push(c.left);
                }else if(c.right != null && h != c.right){
                    stack.push(c.right);
                }else{
                    System.out.print(stack.pop() + " ");
                    h = c;
                }
            }
        }
        System.out.println();
}


测试函数:

 public static void main(String[] args) {

        PrintTree pt = new PrintTree();

        /*

              建树
               1
            /     \
           2       3
         /   \    /  \
        4     5  6    7

       */
        Node root = new Node(1);//创建根结点
        root.left = new Node(2);
        root.right = new Node(3);
        root.left.left = new Node(4);
        root.left.right = new Node(5);
        root.right.left = new Node(6);
        root.right.right = new Node(7);

        pt.preOrderUnRecur(root);
        System.out.println();


        pt.inOrderUnRecur(root);
        System.out.println();

        pt.posOrderUnRecur(root);
        System.out.println();

        pt.posOrderUnRecur2(root);
        System.out.println();

}


测试结果:


猜你喜欢

转载自blog.csdn.net/hoji_James/article/details/80601720