今天有点时间, 根据我下面的想法写了代码.
node_t*
find(node_t* t, int k)
{
if(t == NULL)
return NULL;
/* t1 is used to record the parent of the last node
* which is right child of its parent
*/
t1 = NULL;
do{
if(k < t->v)
t = t->l;
else if(k = t->v)
break;
else{
t1 = t;
t = t->r;
}
}while(t != NULL);
if(t == NULL || t->l == NULL)
return t1;
/* max(t->l) */
t = t->l;
while(t->r != NULL)
t = t->r;
return t;
}
以前的答案
遍历的话, 时间复杂度O(n). 这里有O(lgn)的方法.
就是求 bst的 某节点的 前驱.查询bst, 如果找到 key的节点, 查此节点的前驱; 否则, 可以知道此key 应该插入的节点位置, 查此位置的前驱.
求bst节点 n的 前驱:
如果左子树不为null, 则前驱为 max(n->left);
否则, 递归n的 父节点p; 如果p为根节点, 则前驱为 根节点;
否则, 如果p为其父节点的右节点, 则前驱为 p;
否则, p = p->p; 重复step2-4.
如果bst节点是有父节点信息的. 很简单:
node_t*
max(node_t* r)
{
while(r->r != NULL)
r = r->r;
return r;
}
node_t*
predecessor(node_t* r)
{
if(r->l != NULL)
return max(r->l);
node_t *p = r->p;
while(p != NULL && r != p->r){
r = p;
p = p->p;
}
return p;
}
这里时间O(lgn).
没有父节点信息, 则需要辅助内存. 这里可以用一个 辅助栈 把bst查询 的路径节点都记录下来, 然后就可以 像上述算法一样, 递归查询节点的 父节点了. 时间O(lgn), 空间O(lgn).
当然我们还可以在bst查询时, 记录下其 路径上的 最后一个 "为其父节点的右节点的节点", 这样时间O(lgn), 空间O(1).