繁体   English   中英

C ++ std :: set与自定义的lower_bound

[英]C++ std::set with a custom lower_bound

如何使用独立于其键的比较器函数在std::set上执行find()lower_bound()函数,使其仍在O(log N)时间运行?

假设我定义了具有两个变量xy的数据类型foo ,并具有一个将x作为键值的std::set<foo>

struct foo {
    int x, y;
    foo(int x, int y) : x(x), y(y) {}
};

struct xCompare {
    bool operator() (const foo& i, const foo& j) const {
        return i.x < j.x;
    }
};

// Within main()
std::set<foo, xCompare> fooSetX;

是否可以使用lower_bound()或其他一些比较y值的函数来执行二进制搜索?

为了这个参数,假设xy是唯一且彼此独立的,并且给定两个foo变量foo1foo2 ,如果foo1.x < foo2.x ,则foo1.y < foo2.y 这意味着我不能将y表示为x的函数,但是在fooSetX也由y fooSetX

例如,给定fooSet三个foo(x,y)值(2,5),(3,9)和(5,10 lower_bound() ,将y = 7作为搜索项的lower_bound()将返回迭代器指向至(3,9)。

目前,我要解决此问题的方法是拥有两个std::set<foo> ,分别按xy排序。 每当我需要按y搜索时,我都使用第二个std::set

struct yCompare {
    bool operator() (const foo& i, const foo& j) const {
        return i.y < j.y;
    }
};

// Within main()
std::set<foo, yCompare> fooSetY;

// Inserting elements
fooSetX.insert(foo(2,5)); fooSetY.insert(foo(2,5));
fooSetX.insert(foo(3,9)); fooSetY.insert(foo(3,9));
fooSetX.insert(foo(5,10)); fooSetY.insert(foo(5,10));

// lower_bound() with y = 7
std::set<foo>::iterator it = fooSetY.lower_bound(foo(0,7)); // points to (3,9)

您不能直接将自定义比较器传递给std::set::lower_bound您需要将其传递给类模板本身,因为它将在内部用于维护对象的顺序(因此使std::set::lower_bound工作)

这是std::set模板的定义方式

template<
    class Key,
    class Compare = std::less<Key>,
    class Allocator = std::allocator<Key>
> class set;

Compare唯一的排序自定义点,它允许您提供一个函数对象 ,该函数对象将根据需要代替std::less<Key>来比较您的对象。

无法将其他排序谓词添加到std::set


如果您希望对对象进行其他排序以实现O(log N)查找,则可以使用与原始对象保持同步的另一有序结构。 一个std::set指向第一个使用不同比较器的对象的指针集可以工作。 例:

class MySet
{
private:
    std::set<Item, Comparator0> _set0;
    std::set<decltype(_set0.begin()), Comparator1> _set1;

public:
    void insert(Item x) 
    {
        auto res = _set0.insert(x);
        assert(res.second);

        _set1.insert(res.first);
    }

    const auto& lookup0(Key0 x) { return _set0.lower_bound(x); }
    const auto& lookup1(Key1 x) { return *(_set1.lower_bound(x)); }
};

不使用std :: set,就像@Vittorio Romeo在他的答案中指出的那样。

有一个可以由不相关成员查找的boost数据结构 ,您可以定义为

struct foo {
    int x, y;
    foo(int x, int y) : x(x), y(y) {}
};

// helpers
struct x_tag {}; 
struct y_tag {};

boost::multi_index_container<
    foo,
    indexed_by<
        ordered_unique<tag<x_tag>, boost::multi_index::member<foo, int, &foo::x>>, // std::less<int> applied to foo::x
        ordered_unique<tag<y_tag>, boost::multi_index::member<foo, int, &foo::y>> // std::less<int> applied to foo::y
    >
> fooSet;

int an_x, an_y;
// lookup by x
fooSet.get<x_tag>().find(an_x);
fooSet.get<y_tag>().find(an_y);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM