欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-06-07 21:14:39
...

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


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

过程:

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();

}


测试结果:

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