Pre-order, middle-order, and post-order traversal (recursion and iteration) of binary tree (& BST), the construction of java BST

About pre-order middle-order post-order traversal

Insert picture description here
For example, a normal full node in the above figure, A: root node, B: left node, C: right node, the preorder order is ABC (the root node is the first, then the same level first left and then right); the middle order is BAC (Left first, then root, last right); the subsequent order is BCA (first left, then right, last root).
They are named by the location visited by the root node (the current node), and they are all implemented with dfs.
Front order:
left and right root Middle order: left root right
After order: left root middle

It is better to understand the pre-order, middle-order and post-order with the practical recursive idea.
For example, the middle sequence:
every time you arrive at a new node, one thing you have to consider is the left root right. The current node is the root.
You need to find the left first. (Or is traversing the left and right to access the current traversing this may better understand some)
so, the face of such a binary tree:
Insert picture description here
preorder traversal: ABCDEFGHK

Mid-order traversal: BDCAEHGKF

Post-order traversal: DCBHKGFEA

java code implementation-recursion

prologue:

void dfs(TreeNode root) {
    
    
    visit(root);
    dfs(root.left);
    dfs(root.right);
}

Middle order:

void dfs(TreeNode root) {
    
    
    dfs(root.left);
    visit(root);
    dfs(root.right);
}

After sequence:

void dfs(TreeNode root) {
    
    
    dfs(root.left);
    dfs(root.right);
    visit(root);
}

Specific example: LeetCode144 Binary Tree Pre-order Traversal
Details of the topic: Give you the root node root of the Binary Tree, and return the pre-order traversal of its node value.

class Solution {
    
    
    public List<Integer> preorderTraversal(TreeNode root) {
    
    
        List<Integer> visited = new LinkedList<>();
        dfs(root,visited);
        return visited;

    }

    public void dfs(TreeNode s, List<Integer> visited){
    
    
        if(s==null){
    
    
            return;
        }
        visited.add(s.val);
        dfs(s.left,visited);
        dfs(s.right,visited);
        return;
    }
}

Similar in subsequent order and middle order

java code implementation-iteration

The iteration here actually uses the stack to simulate the idea of ​​recursion.
Because in fact recursion is also a call to the stack.

prologue

public List<Integer> preorderTraversal(TreeNode root) {
    
    
    List<Integer> visited = new ArrayList<>();
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);
    while (!stack.isEmpty()) {
    
    
        TreeNode s = stack.pop();
        if (s == null) continue;
        visited.add(s.val);
        stack.push(s.right);  // 先右后左,保证左子树先遍历
        stack.push(s.left);
    }
    return visited;
}

The stack is used here, the stack is first in, last out.
Therefore, non-recursion is used here. In order to ensure the preorder, the current node is added first. In
then in order to ensure that after the first left and right, so here is the right first stack, stack the left rear. Left right

For the post-order: the
pre-order traversal is root -> left -> right, and the post-order traversal is left -> right -> root. You can modify the pre-order traversal to root -> right -> left, then this order is exactly the opposite of the post-order traversal.

public List<Integer> postorderTraversal(TreeNode root) {
    
    
    List<Integer> ret = new ArrayList<>();
    Stack<TreeNode> stack = new Stack<>();
    stack.push(root);
    while (!stack.isEmpty()) {
    
    
        TreeNode node = stack.pop();
        if (node == null) continue;
        ret.add(node.val);
        stack.push(node.left);
        stack.push(node.right);
    }
    Collections.reverse(ret);
    return ret;
}

Middle sequence:
This is a bit more troublesome. In each step, we first put the left child node into the stack until the left child node is empty, then visit, and then put the right child node into the stack, and so on.
The logic here is:
first push all the left into the stack,
then visit the current node,
and then push the right node into the stack (the right node in the code below is not pushed into the stack, because if there is a push here, the top of the while still needs to be out of the stack. , This will greatly increase the time complexity, it is not necessary. The nodes used at the bottom and the top of the while are the same node, so there is no need to stack and pop to increase the overhead. However, it can be understood as stacking)

class Solution {
    
    
    public List<Integer> inorderTraversal(TreeNode root) {
    
    
        List<Integer> ret = new ArrayList<>();
        if (root == null) return ret;
        Stack<TreeNode> stack = new Stack<>();
        TreeNode cur = root;
        while (cur != null || !stack.isEmpty()) {
    
    
            while (cur != null) {
    
    
                stack.push(cur);
                cur = cur.left;
            }
            TreeNode node = stack.pop();
            ret.add(node.val);
            cur = node.right;
        }
        return ret;
    }
}

Morris traversal of binary tree

For the implementation of the above recursive traversal, in fact, it is necessary to rely on the stack. In Java, due to the limitation of the jvm on the virtual machine stack, it will cause the stack to overflow when the amount of data is relatively large, so sometimes, we need a complicated space The way to traverse is smaller.
The morris traversal here means that a certain time complexity is sacrificed in exchange for O(1) space complexity.
Since in recursion, the bottom element is returned as the upper element, relying on the stack, there is no stack here.
Instead, a clever way is adopted, that is, at this point, the rightmost point of the left subtree points to this point, so naturally, it simulates the operation of popping the upper element from the stack, so that it can return to the upper element. (This is called setting clue in Morris)
Then after the visit, the clue has to be deleted. This is the same as the element that was popped out of the stack and discarded after the visit, which can avoid the modification of the binary tree.
Then, in the previous traversal, the preorder is traversed once for each point and printed, while the middle order is traversed twice and printed, and the postorder is traversed and printed three times. Morris did imitate this.
In the morris implementation of pre-order, middle-order and post-order, the first two implementations are relatively simple. I don’t see any problem and can also be used. The latter is a bit awkward, and the linked list needs to be flipped. Mark here first. The application scenarios are relatively more. Come back and understand when you need it.
First put two blogs that you think are well written to save time:
https://blog.csdn.net/wdq347/article/details/8853371
https://blog.csdn.net/pcwl1206/article/details/96977808

For the binary search tree BST, the in-order traversal to get the ordered sequence

As in the title
, the feature of BST here is that all the values ​​of the left subtree <= the value of the root node <= the value of the right subtree

Creation of BST (Balance)

The balance lies in finding the middle point each time, so it can be guaranteed to be balanced (the difference in depth between the left and right subtrees is no more than 1).
In fact, I want to build a BST, which is not guaranteed to be balanced. Just choose a value in the middle of the entire interval as the point. The value is enough, then the left subtree is the left of the point in the interval, and the right subtree is the right of the point in the interval. Such logic can ensure that the root node is greater than or equal to all the values ​​of the left subtree, and less than or equal to all the values ​​of the right subtree, thereby constructing a BST.
And when I only consider the middle position each time I choose a value, it means that in each round, the difference between the number of left and right subtrees does not exceed 1, and then it will eventually be balanced.
(At the same time, the purpose of using medium = l + (rl)/2 here is to prevent overflow. If (r+l)/2 is used, r+l may overflow, and rl is never possible to overflow)

class Solution {
    
    
    public TreeNode sortedArrayToBST(int[] nums) {
    
    
        return dfs(nums,0,nums.length-1);

    }

    public TreeNode dfs(int[] nums,int l, int r){
    
    
        if(l>r){
    
    
            return null;
        }
        int medium = l+(r-l)/2;
        TreeNode node = new TreeNode(nums[medium]);
        node.left = dfs(nums,l,medium-1);
        node.right = dfs(nums,medium+1,r);
        return node;
    }
}

reference

https://blog.csdn.net/qq_33243189/article/details/80222629
LeetCode

Guess you like

Origin blog.csdn.net/qq_34687559/article/details/109369006