leetcode: 145. Post order traversal of binary tree

Keywords: Algorithm data structure

1: Recursive implementation

void endTraversal(struct TreeNode *root,int *ret,int *returnSize)
{
    if(root)//If the tree is not empty, it will traverse, and if it is empty, it will end
    {
        endTraversal(root->left,ret,returnSize);//Postorder traversal of left subtree
        endTraversal(root->right,ret,returnSize);//Postorder traversal right subtree
        ret[(*returnSize)++]=root->val;//First left, then right, and finally deal with intermediate nodes
    }
}
int* postorderTraversal(struct TreeNode* root, int* returnSize){
    int *ret=(int *)malloc(sizeof(int)*100);
    *returnSize=0;
    endTraversal(root,ret,returnSize);
    return ret;
}

2: A clever way

1: On the premise that you can traverse first.

2: Because the preorder traversal is in the left and right traversal order, change the preorder traversal order to record the middle right and left in the array, and finally reverse the array is the output in the left and right.

3: In this way, you can output the order of post order traversal, but it is not the way to access the left subtree first, the right subtree and finally the root node, so it is a clever way.

3: Clever code

int* postorderTraversal(struct TreeNode* root, int* returnSize){
    int *ret=(int *)malloc(sizeof(int)*100);
    *returnSize=0;
    struct TreeNode *stack[100];
    int top=0;
    if(root==NULL)
    {
        return ret;
    }
    stack[0]=root;
    while(top>=0)
    {
        struct TreeNode *temp=stack[top--];//Pop up the root node and save it
        if(temp->left!=NULL)//If the left subtree is not an empty tree, put it on the stack
        {
            stack[++top]=temp->left;
        }
        if(temp->right!=NULL)//If the right subtree is not empty, it is put on the stack and reaches the processing order of middle right and left
        {
            stack[++top]=temp->right;
        }
        ret[(*returnSize)++]=temp->val;//Process the saved root node first
    }
    int i=0,j=(*returnSize)-1;
    struct TreeNode *temp1;
    while(i<j)//Because the stored array is in the middle right and left, the inverted array is in the left and right
    {
        temp1=ret[i];
        ret[i]=ret[j];
        ret[j]=temp1;
        i++;
        j--;
    }
    return ret;
}

4: Iterative thought

1: Let's first recall the middle order traversal process. First put the root node on the stack. The root node represents the node itself and the right subtree, and then put the left subtree on the stack. First pop up the top node of the stack to process the left subtree, then pop up the root node and save it, and put the right subtree represented by the root node on the stack to achieve the processing order of first left, then middle and then right.

2: If you understand the middle order traversal, it is not difficult to understand that each node in the stack is the sum of itself and the right subtree. The pop-up node must be the node processed by the left subtree. After pop-up, first process the intermediate node, and then put the right subtree represented by the intermediate node into the stack. The right subtree after stack can actually be regarded as a new tree, It represents the sum of itself and the right subtree of the new tree.

3: Whether the post order traversal process can also be roughly the same as the middle order traversal, because the required access order is left and right middle, or the same idea. First put the root node into the stack with its node itself and the right subtree, and then put the left subtree into the stack. First pop up the top node of the stack to process the left subtree, then pop up the root node and save it to process the right subtree represented by the root node, And put the root node on the stack again (think about the difference between putting the root node on the stack again and putting the right subtree represented by the intermediate node traversed in the middle order on the stack again).

4: After the right subtree represented by the intermediate node traversed in the middle order is stacked again, the right subtree after stacking is regarded as a new tree, which represents the sum of the root node itself and the right subtree of the new tree. However, after the root node traversed in the post order is put into the stack again, it does not represent the sum of the root node and its right subtree. Because the right subtree has been processed first, there are two kinds of nodes in the stack. One node represents the sum of the root node and the right subtree, and the other only represents its own nodes.

5: The node representing the sum of the root node and the right subtree. After being out of the stack, the right subtree is processed, and the root node is also put into the stack; However, it only represents its own node. After it is out of the stack, it can directly process itself (because its right subtree has been out of the stack).

6: We need to distinguish these two different nodes. After the right subtree is out of the stack, a null pointer is put into the stack behind the node that is put into the stack again. If NULL is encountered during the out of the stack, it means that the next element only needs to deal with itself.

5: Iterative code

int* postorderTraversal(struct TreeNode* root, int* returnSize){
    int *ret=(int *)malloc(sizeof(int)*100);
    *returnSize=0;
    struct TreeNode *stack[100];
    int top=0;
    if(root==NULL)
    {
        return ret;
    }
    stack[0]=root;
    while(top>=0)
    {
        while(stack[top]->left!=NULL)
        {
            struct TreeNode *temp=stack[top];
            stack[++top]=temp->left;
        }
        while(top>=0)
        {
            struct TreeNode *temp1=stack[top--];
            while(temp1==NULL)//This indicates that the right subtree has been processed and the root node is processed directly
            {
                temp1=stack[top--];
                ret[(*returnSize)++]=temp1->val;
                if(top<0)
                {
                    return ret;
                }else
                {
                    temp1=stack[top--];
                }
            }
            if(temp1->right!=NULL)
            {
                stack[++top]=temp1;//Because the right subtree needs to be processed first, the root node also needs to be stacked
                stack[++top]=NULL;//Because the right subtree of the root node has been expanded, you need to add a null pointer to the root node for marking
                stack[++top]=temp1->right;//Right subtree stack
                break;//If the right subtree is not empty, the right subtree is regarded as a new tree and the above operation is repeated
            }else//If the right subtree is empty, it means that the left and right subtrees are processed and the intermediate nodes are processed
            {
                ret[(*returnSize)++]=temp1->val;
                printf("%d ",temp1->val);
            }
        }
    }
    return ret;
}

Posted by the_924 on Wed, 01 Dec 2021 17:24:49 -0800