Non-recursive traversal of binary trees for data structures and algorithms

Non-recursive traversal of a binary tree

preorder traversal

logic:

  1. Visit node P and push node P into the stack;
  2. Determine whether the left child of node P is empty, if it is empty, take the top node of the stack and pop it out, set the right child of the top node as the current node P, and loop to 1; if not is empty, set the left child of P as the current node P;
  3. Until P is NULL and the stack is empty, the traversal ends.

Code

/**  
 * 非递归前序遍历二叉树  
 * 1. 访问结点 P,并将结点 P 入栈;  
 * 2. 判断结点 P 的左孩子是否为空,若为空,则取栈顶结点并进行出栈操作,并将栈顶结点的右孩子置为当前的结点 P,循环至1;  
 * 若不为空,则将 P 的左孩子置为当前的结点 P;  
 * 3. 直到 P 为 NULL 并且栈为空,则遍历结束。  
 *  
 * @param p 根节点  
 */  
void preOrderByStack(TreeNode p) {  
    Stack<TreeNode> stack = new Stack<>();  
    stack.push(p);  
    while (p != null || !stack.empty()) {  
        while (p != null) {  
            System.out.println(p.val);  
            stack.push(p);  
            p = p.left;  
        }  
        if (!stack.empty()) {  
            p = stack.pop();  
            p = p.right;  
        }  
    }  
}

Inorder traversal

logic:

For any node P,

  1. If its left child is not empty, push P into the stack and set the left child of P as the current P, and then perform the same processing on the current node P;
  2. If its left child is empty, take the top element of the stack and pop it out, visit the top node of the stack, and then set the current P as the right child of the top node of the stack;
  3. Until P is NULL and the stack is empty, the traversal ends

Code

/**  
 * 非递归前序遍历二叉树  
 * 1. 若其左孩子不为空,则将 P 入栈并将 P 的左孩子置为当前的 P,然后对当前结点 P 再进行相同的处理;  
 * 2. 若其左孩子为空,则取栈顶元素并进行出栈操作,访问该栈顶结点,然后将当前的 P 置为栈顶结点的右孩子;  
 * 3. 直到 P 为 NULL 并且栈为空则遍历结束  
 *  
 * @param p 根节点  
 */  
void midOrderByStack(TreeNode p) {  
    Stack<TreeNode> stack = new Stack<>();  
    stack.push(p);  
    while (p != null && !stack.empty()) {  
        while (p != null) {  
            stack.push(p);  
            p = p.left;  
        }  
        if (!stack.empty()) {  
            p = stack.pop();  
            System.out.println(p.val);  
            p = p.right;  
        }  
    }  
}

Post-order traversal (a bit more complicated)

The non-recursive implementation of postorder traversal is the most difficult of the three traversal methods. Because in the post-order traversal, it is necessary to ensure that both the left child and the right child have been visited and the left child can only visit the root node before the right child, which brings difficulties to the control of the process. Two ideas are introduced below. You can observe the brainstorming picture below:

insert image description here

method one

The first way of thinking: For any node P, push it into the stack, and then search down its left subtree until a node without a left child is found. At this time, the node appears on the top of the stack, but this It cannot be popped and accessed at the time, so its right child has not been accessed yet. So then follow the same rules to perform the same processing on its right subtree. When its right child is visited, the node appears on the top of the stack again, and it can be popped and accessed at this time. This ensures correct access order. It can be seen that in this process, each node appears on the top of the stack twice, and it can only be accessed when it appears on the top of the stack for the second time. Therefore, it is necessary to set an additional variable to identify whether the node appears on the top of the stack for the first time.

This method needs to re-apply for a structure. Method 2 is recommended here.

Method Two

logic:

It is recommended to watch the video : Binary tree traversal - postorder (non-recursive) [graphic + code]_哔哩哔哩_bilibili


  1. First, set a variable to record the right node visited here as prean example, then traverse all left nodes and push them into the stack;
  2. Determine whether the top element of the stack has a right node (the pop-up operation has not yet been performed at this time)
    1. If there is a right node and has been visited or there is no right node , it will be output directly, and pre will be set as the current node cur, and the current node p will be set to empty, so as to prevent the next cycle from repeatedly traversing the left subtree, and finally set The top element of the stack is popped
    2. There is a right node but has not been visited, set the current node as the right node, and traverse the right node tree, that is, set the current node as the right node and repeat the first cur.rightstep

Code

/**  
 * 非递归后序遍历二叉树  
 *  
 * @param p 根节点  
 */  
void rearOrderByStack(TreeNode p) {  
    Stack<TreeNode> stack = new Stack<>();  
    stack.push(p);  
    TreeNode pre = null;  
    while (p != null || !stack.empty()) {  
        while (p != null) {  
            stack.push(p);  
            p = p.left;  
        }  
        if (!stack.empty()) {  
            p = stack.peek();  
        }  
        assert p != null;  
        //栈顶有右子树且未被访问过  
        if (p.right != null && p.right != pre) {  
            p = p.right;  
        } else {  
            //访问当前结点  
            System.out.println(p.val);  
            pre = p;  
            //此时p是栈顶元素,直接将p置空,下次循环直接就是获取栈顶元素,避免重复访问左子树  
            p = null;  
            stack.pop();  
        }  
    }  
}

Guess you like

Origin blog.csdn.net/qq_45074341/article/details/126856448