在二叉搜索树中找到第k个最小元素

时间:2012-04-28 11:10:08

标签: c++ binary-search-tree

我编写了一个算法,用于在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) {}
};

2 个答案:

答案 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->countnode的整个子树中的节点数。 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

我没有测试过建议的更改,但是它们应该为您提供正确的进展方向