Reputation: 51
A problem from CLRS ,3ed.
12.3-5
Suppose that instead of each node x keeping the attribute x.p, pointing to x’s parent, it keeps x.succ, pointing to x’s successor. Give pseudocode for SEARCH,INSERT, and DELETE on a binary search tree T using this representation. These procedures should operate in time O(h), where h is the height of the tree T . (Hint:You may wish to implement a subroutine that returns the parent of a node.)
I know how to implement a subroutine that returns the parent of a node in O(h) time.
To find the parent of node x
, we should find the maximum key M
in the subtree rooted at x
first. Then, we go downward to the right from M.succ.left
. When we reach x
, the node we encounter before x
is x
's parent.
See the code.
typedef struct TREE{
struct TREE* left,right,succ;
}*BST;
PARENT(BST x)
{
if(x==root) return NULL;
BST max=TREE_MAXIMUM(x);
BST parent=max->succ,t;
if(parent) t=parent->left;
else t=root;
while(t!=x){parent=t;t=t->right;}
return parent;
}
When DELETE
x
, the succ of x
's predecessor should be modified to point to x.succ
, no longer x
. So now comes the problem--how to find the predecessor of x
in O(h) time?
When the left subtree of x
is nonempty, it's the rightmost node in x
's left subtree. However, when the left subtree of x
is empty, the predecessor is x
's ancestor, to find which calls O(h) times of PARENT
. Does that needs O(h*h) time? Or should we search downward from the root?
Notice that the operation INSERT
, also needs to find a node's predecessor.
There comes a question--what if all the keys share the same value? Then we cannot find x
's predecessor using comparison, for the key a
, which equals to key x
, may appears in x
's left subtree or right subtree.
Upvotes: 3
Views: 1724
Reputation: 101
Note : O(h) is only possible if the root is directly available.(which should be the case)
Changing your data structure a bit.
typedef struct TREE{
int key;
struct TREE* left,right,succ;
}*BST;
If the left sub-tree is non-empty we use TREE_MAXIMUM, otherwise we search for x in the BST starting the search from root and maintain(in variable goal) the last(i.e latest) node encountered with a right child. At the end of the search, goal is the predecessor.
Predecessor function
BST PRE(BST x)
{
if(x->left!=NULL)
return TREE_MAXIMUM(x->left);
if(x== root)
return NULL;
BST goal = NULL, y = root;
while(1)
{
if(x->key <= y->key)
y=y->left;
else
{
goal=y;
y=y->right;
}
if(x==y)
{
return goal;
}
}
}
Upvotes: 0
Reputation: 2456
If keys are discrete, the predecessor of x has key that is <= key(x)-1 right? And if you search the tree for key(x)-1 what happens? Don't you necessarily run into pred(x) during that traverse? You'd have to double-check me on that. And of course non-discrete keys (e.g. floating point) could be problematic (as to -1).
Upvotes: 0
Reputation: 8147
In case the left subtree of x
is empty, the predecessor of x
is not just its ancestor, it's the direct parent of x
. So you only need a single call to the parent
subroutine, making the over all runtime O(h)+O(h)=O(h)
.
P.S
Even if it wasn't the direct parent, you still don't have to call parent
repeatedly to get all ancestors, you can just start searching for x
from the root of the tree as you normally would, saving all of the nodes along the path to x
in a single traversal of length O(h)
. All of the nodes you pass through when searching for x
, and only those nodes, are by definition the ancestors of x
.
Upvotes: 1