我编写了一个算法,用于在BST中查找第n个最小元素,但它返回根节点而不是第n个最小元素。因此,如果按顺序输入节点7 4 3 13 21 15,则此算法在调用find(root,0)后返回值为7而不是3的节点,对于调用find(root,1),它返回13而不是4。想法?
Binode* Tree::find(Binode* bn, int n) const
{
if(bn != NULL)
{
find(bn->l, n);
if(n-- == 0)
return bn;
find(bn->r, n);
}
else
return NULL;
}
和Binode的定义
class Binode
{
public:
int n;
Binode* l, *r;
Binode(int x) : n(x), l(NULL), r(NULL) {}
};
答案 0 :(得分:2)
不可能自己有效地检索二叉搜索树中的第n个最小元素。但是,如果在每个节点中保留一个整数,表示整个子树中的节点数,则可以实现这一点。来自my generic AVL tree implementation:
static BAVLNode * BAVL_GetAt (const BAVL *o, uint64_t index)
{
if (index >= BAVL_Count(o)) {
return NULL;
}
BAVLNode *c = o->root;
while (1) {
ASSERT(c)
ASSERT(index < c->count)
uint64_t left_count = (c->link[0] ? c->link[0]->count : 0);
if (index == left_count) {
return c;
}
if (index < left_count) {
c = c->link[0];
} else {
c = c->link[1];
index -= left_count + 1;
}
}
}
在上面的代码中,node->link[0]
和node->link[1]
是node
的左右子项,node->count
是node
的整个子树中的节点数。 1}}。
假设树是平衡的,上述算法具有O(logn)时间复杂度。此外,如果保留这些计数,则可以进行另一项操作 - 给定指向节点的指针,可以有效地确定其索引(与您要求的相反)。在我链接的代码中,此操作称为BAVL_IndexOf()
。
请注意,当树更改时,需要更新节点计数;这可以通过时间复杂度的(渐近)变化来完成。
答案 1 :(得分:1)
您的代码存在一些问题:
1)find()
返回一个值(正确的节点,假设函数按预期工作),但是你没有将该值传播到调用链上,所以顶层调用不知道(可能的)找到的元素
Binode* elem = NULL;
elem = find(bn->l, n);
if (elem) return elem;
if(n-- == 0)
return bn;
elem = find(bn->r, n);
return elem; // here we don't need to test: we need to return regardless of the result
2)即使您在正确的位置执行n
的递减,更改也不会在调用链中向上传播。您需要通过引用传递参数(请注意函数签名中&
之后的int
),因此对原始值进行更改,而不是对其副本进行更改
Binode* Tree::find(Binode* bn, int& n) const
我没有测试过建议的更改,但是它们应该为您提供正确的进展方向