I was asked to implement a binary search tree with follow operation for each node v - the complexity should be O(1). The follow operation should return a node w (w > v).
I proposed to do it in O(log(n)) but they wanted O(1)
Upd. It should be next greater node
-
1And your question is...Maroun– Maroun2013-11-29 07:33:52 +00:00Commented Nov 29, 2013 at 7:33
-
You can only get amortized O(1) for this operation. Worst case is still O(log(n)). Did you try showing that?Domi– Domi2013-11-29 07:36:10 +00:00Commented Nov 29, 2013 at 7:36
-
I'm not sure if I am correct, but If you maintain pointers to parents for all left children, For every node v, if v->right exists then it shall be greater than v. Else, if it is a left child, then its parent shall be greater than the node.Abhishek Bansal– Abhishek Bansal2013-11-29 07:45:25 +00:00Commented Nov 29, 2013 at 7:45
-
I assume you still need insert/delete operations, i.e. tree is dynamic, right?ile– ile2013-11-29 07:45:52 +00:00Commented Nov 29, 2013 at 7:45
-
@ile Yes,insert and delete operations shall not be O(1), but follow operation shall be.Abhishek Bansal– Abhishek Bansal2013-11-29 07:46:47 +00:00Commented Nov 29, 2013 at 7:46
4 Answers
just keep the maximum element for the tree and always return it for nodes v < maximum.
4 Comments
You can get O(1) if you store pointers to the "next node" (using your O(log(n) algorithm), given you are allowed to do that.
5 Comments
How about:
int tree[N];
size_t follow(size_t v) {
// First try the right child
size_t w = v * 2 + 1;
if(w >= N) {
// Otherwise right sibling
w = v + 1;
if(w >= N) {
// Finally right parent
w = (v - 1) / 2 + 1;
}
}
return w;
}
Where tree is a complete binary tree in array form and v/w are represented as zero-based indices.
Comments
One idea is to literally just have a next pointer on each node.
You can update these pointers in O(height) after an insert or remove (O(height) is O(log n) for a self-balancing BST), which is as long as an insert or remove takes, so it doesn't add to the time complexity.
Alternatively, you can also have a previous pointer in addition to the next pointer. If you do this, you can update these pointers in O(1).
Obviously, in either case, if you have a node, you also have its next pointer, and you can simply get this value in O(1).
Pseudo-code
For only a next pointer, after the insert, you'd do:
if inserted as a right child:
newNode.next = parent.next
parent.next = newNode
else // left child
predecessor(newNode)
For both next and previous pointers:
if inserted as a right child:
parent.next.previous = newNode
newNode.next = parent.next
parent.next = newNode
else // left child
parent.previous.next = newNode
newNode.previous = parent.previous
parent.previous = newNode
(some null checks are also required).