Let $n$ represent the next element to be inserted. Let $P(y)$ represent the parent of node $y$.
- We will read the traversal in reverse. The last element of the traversal is the root. Let $l = root$. $l$ will represent the element last inserted in the BST (except for the 3rd case below- where it will change to the parent).
Loop the following till there’s no element left to be inserted
- if $l<n$ then $n$ is the right child of $l$. For the next insertion, $l$ changes to it’s right child and $n$ becomes the next element(in reverse order of traversal ).
- else, if $l>n$ and $P(l)<n$ then $n$ is the left child of $l$. For the next insertion, $l$ changes to it’s left child and $n$ becomes the next element(in reverse order of traversal).
- else, if $l>n$ and $P(l)>n$ then $l$ becomes $P(l)$.($n$ hasn’t been inserted – we loop with $l$ changed)
[Let $P(root)=- infty$, so that the $2^{nd}$ case applies]
Complexity Analysis : Every element may contribute at max 3 comparisons, 1 each for – left child, right child and for finally leaving i.e. subtree has been constructed. Even if I missed a comparison or two, It should be constant no. of comparisons per element and no. of operations for node construction will also be constant per element. Hence, giving $O(k)$ time complexity. Actual Question If the algorithm is correct, I need the correctness proof for it. Yes, I thought I had the proof but then brain got fried and I am stuck and unable to reason succinctly.
If the algorithm is incorrect, then why? And what is time complexity of the most efficient algorithm for the same question? Also, is the $O(k)$ complexity correctly calculated – irrespective of the correctness of the algorithm?
Asked By : atulgangwar
Answered By : Terence Hang
Let $n$ represent the next element to be inserted. Let $P(y)$ represent the parent of node $y$. Let $g=G(y)$ represent the first node g on the path $yto root$ such that $P(g)<g$.
- We will read the traversal in reverse. The last element of the traversal is the root. Let $l = root$. $l$ will represent the element last inserted in the BST (except for the 3rd case below- where it will change to the parent). Let $g=root$ tracking $G(l)$, initialize empty stack $stkG$ storing previous $g$’s on current path.
- Loop the following till there’s no element left to be inserted
- if $l<n$ then $n$ is the right child of $l$. For the next insertion, $l$ changes to it’s right child and $n$ becomes the next element(in reverse order of traversal ). Push $g$ on $stkG$, and let $g=l$.
- else, if $l>n$ and $textbf{P(g)<n}$ then $n$ is the left child of $l$. For the next insertion, $l$ changes to it’s left child and $n$ becomes the next element(in reverse order of traversal).
- else, if $l>n$ and $textbf{P(g)>n}$ then $l$ becomes $textbf{P(g)}$ and pop $g$ from $stkG$.($n$ hasn’t been inserted – we loop with $l$ changed)
[Let $P(root)=- infty$, so that the $2^{nd}$ case applies]
For correctness, you can prove the following loop invariant:
- Root is the first inserted element. for each insertion except root, the parent element has been inserted before.
- Each insertion $n$ correctly maintains the order between $n$ and $l$. ($n<l$ if $n$ is left child of $l$, $n>l$ otherwise)
- After backtracking step 3, the next insertion always occurs on the left branch.
1 and 3 ensures the post-order traversal, while 2 ensures the BST. For complexity:
- insertion cost: each element is inserted exactly once.
- traversal and comparison: the algorithm actually performs a post-order traversal in reverse order, with $O(1)$ comparison on each step.
- $g$,$stkG$ maintain cost: each node, which is right child of parent, is pushed and popped from $stkG$ at most once.
Thus the time complexity is $O(k)$.
Alternative algorithm:[1]
Using a recursive procedure:
procedure BST_from_postorder(post, len, target) /* input: post[0..len-1] -- (partial) postorder traversal of BST len -- length of post to be processed. target -- a cutoff value to stop processing Output: tree_ptr -- pointer to root of tree/sub tree constructed from post[len_rest..len-1] len_rest -- remaining length that has not been processed. */ 1. if len <= 0 or post[len-1] <= target, then return null. 2. root <- new Node created from from post[len-1]. 3. (root->right, new_len) <- BST_from_postorder(post, len-1, post[len-1]) 4. (root->left, rest_len) <- BST_from_postorder(post, newlen, target) 5. return (pointer to root, rest_len) /* BST_from_postorder(post, length of post, -infinity) will return the BST construct from given postorder traversal. */
Best Answer from StackOverflow
Question Source : http://cs.stackexchange.com/questions/46893