Non-recursive post-order traversal of binary tree summary (2 methods)

Algorithm non-recursive post-order traversal of binary tree summary (2 methods)

@author:Jingdai
@date:2020.12.04

Portal

method 1

The non-recursive stack is used to assist the traversal. The post-order traversal is the third time that the node is encountered and then traversed, but the stack can only provide us with a judgment method for encountering twice, the first time is when the stack is pushed, and the second is out When stacking, they respectively correspond to the pre-order and middle-order traversal of the binary tree. So we need to use some skills to assist our judgment, which is why the post-order traversal of the binary tree is slightly more complicated than the pre-order and middle-order.

Look at the code for analysis.

public static void postOrderTraverse(TreeNode root) {
    
    

    TreeNode p = root;
    TreeNode pre = null;
    LinkedList<TreeNode> stack = new LinkedList<>();

    while (p != null || stack.size() != 0) {
    
    
        while (p != null) {
    
    
            stack.push(p);
            p = p.left;
        }
        p = stack.pop();
        if (p.right == null) {
    
     // leaf 
            pre = p;
            System.out.println(p.val);
            p = p.right;
        } else if (p.right == pre) {
    
     // pre is p.right
            pre = p;
            System.out.println(p.val);
            p = null;
        } else {
    
      // p.right dont traverse
            stack.push(p);
            p = p.right;
        }
    }
}

The process is basically the same as the pre-order middle-order, so when do we need to traverse? When this node is a leaf node or when the right subtree of this node has been traversed, it can be traversed, otherwise we put it on the stack again and wait for the next traversal. It also shows that only when the node is a leaf node or the right subtree of this node has been accessed, the node can be successfully popped out of the stack.

  • Leaf node judgment

    A leaf node is easy to judge. As long as its right child is null, it means it is a leaf node, because the left child must be null, otherwise it will not jump out of the previous while.

  • Whether the right subtree has been traversed to determine

    See above code, we are successfully carried out in the stack when the traverse, then preorder traversal on the current node traversal of a node is its right child, we prerecorded the last out smoothly stack node, right child to determine if the current node It is the last node that was successfully popped from the stack, which means that the right subtree has been traversed, and the current node is traversed.

Then there is another problem. In the pre-order and middle-order traversal, when a node is popped up, it is directly let p = p.right, and then to visit the right subtree, the post-order traversal is a bit different. When the node is popped up for the first time, the same as the pre-order and middle-order, you need to visit its right sub-tree, p = p.rightbut when the node is popped up for the second time, it is judged that its right sub-tree has been accessed. You can no longer visit the right subtree, or you will end up in an endless loop, you should let p = null, continue popping elements out of the stack.

After understanding the above code, I found that the above two branches can be combined into one, so the final code is as follows.

public static void postOrderTraverse(TreeNode root) {
    
    
        
    TreeNode p = root;
    TreeNode pre = null;
    LinkedList<TreeNode> stack = new LinkedList<>();

    while (p != null || stack.size() != 0) {
    
    
        while (p != null) {
    
    
            stack.push(p);
            p = p.left;
        }
        p = stack.pop();
        // left or pre is p.right
        if (p.right == null || p.right == pre) {
    
     
            pre = p;
            System.out.println(p.val);
            p = null;
        } else {
    
      // p.right dont traverse
            stack.push(p);
            p = p.right;
        }
    }
}

Method 2 Morris method

The Morris method is the same as the pre-order middle order, but its traversal point is different. It traverses the rightmost sequence of its left tree when each node is visited for the second time. But this will cause the rightmost sequence of the entire tree to not be traversed, so at the end, add a rightmost sequence of the entire tree to traverse. This should be the most troublesome binary tree traversal method. code show as below.

public static void postOrderTraverse(TreeNode root) {
    
    

    TreeNode cur = root;
    TreeNode rightmost = null;

    while (cur != null) {
    
    
        if (cur.left != null) {
    
    
            rightmost = cur.left;
            while (rightmost.right != null && rightmost.right != cur) {
    
    
                rightmost = rightmost.right;
            }
            if (rightmost.right == null) {
    
    
                rightmost.right = cur;
                cur = cur.left;
            } else {
    
    
                rightmost.right = null;
                reverseTraverse(cur.left);
                cur = cur.right;
            }
        } else {
    
    
            cur = cur.right;
        }
    }
    reverseTraverse(root);
}

public static void reverseTraverse(TreeNode node) {
    
    
    TreeNode head = reverse(node);
    TreeNode p = head;
    while (p != null) {
    
    
        System.out.println(p.val);
        p = p.right;
    }
    reverse(head);
}

public static TreeNode reverse(TreeNode node) {
    
    
    if (node == null || node.right == null) {
    
    
        return node;
    }

    TreeNode cur = node;
    TreeNode next = node.right;
    TreeNode temp = node.right;
    cur.right = null;
    while (next != null) {
    
    
        temp = next.right;
        next.right = cur;
        cur = next;
        next = temp;
    }
    return cur;
}

Guess you like

Origin blog.csdn.net/qq_41512783/article/details/110667541