[英]C++ std::set with a custom lower_bound
How would I perform a find()
or lower_bound()
function on a std::set
using a comparator function that is independent of its key such that it still runs in O(log N) time? 如何使用独立于其键的比较器函数在
std::set
上执行find()
或lower_bound()
函数,使其仍在O(log N)时间运行?
Suppose I define a data type foo
with two variables x
and y
and have a std::set<foo>
that uses x
as the key value. 假设我定义了具有两个变量
x
和y
的数据类型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;
Is it possible to perform a binary search using lower_bound()
or some other function that compares the values of y
? 是否可以使用
lower_bound()
或其他一些比较y
值的函数来执行二进制搜索?
For the sake of this argument, assume that x
and y
are unique and independent of each other, and that given two foo
variables foo1
and foo2
, if foo1.x < foo2.x
, then foo1.y < foo2.y
. 为了这个参数,假设
x
和y
是唯一且彼此独立的,并且给定两个foo
变量foo1
和foo2
,如果foo1.x < foo2.x
,则foo1.y < foo2.y
。 This means that I cannot express y
as a function of x
, but is also ordered by y
within fooSetX
. 这意味着我不能将
y
表示为x
的函数,但是在fooSetX
也由y
fooSetX
。
For example, given three foo(x,y)
values (2,5), (3,9) and (5,10) within fooSet
, a lower_bound()
that takes y = 7
as the search term would return an iterator pointing to (3,9). 例如,给定
fooSet
三个foo(x,y)
值(2,5),(3,9)和(5,10 lower_bound()
,将y = 7
作为搜索项的lower_bound()
将返回迭代器指向至(3,9)。
Currently, the way I go about solving this is by having two std::set<foo>
s, ordered by x
and y
respectively. 目前,我要解决此问题的方法是拥有两个
std::set<foo>
,分别按x
和y
排序。 Whenever I need to search by y
, I use the second std::set
. 每当我需要按
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)
You cannot directly pass a custom comparator to std::set::lower_bound
- you need to pass it to the class template itself, as it will be internally used to maintain the order of the objects (consequently making std::set::lower_bound
work) . 您不能直接将自定义比较器传递给
std::set::lower_bound
您需要将其传递给类模板本身,因为它将在内部用于维护对象的顺序(因此使std::set::lower_bound
工作) 。
Here's how the std::set
template is defined : 这是
std::set
模板的定义方式 :
template<
class Key,
class Compare = std::less<Key>,
class Allocator = std::allocator<Key>
> class set;
Compare
is the only ordering customization point that allows you to provide a function object that will compare your objects as desired in place of std::less<Key>
. Compare
是唯一的排序自定义点,它允许您提供一个函数对象 ,该函数对象将根据需要代替std::less<Key>
来比较您的对象。
There's no way of adding additional ordering predicates to an std::set
. 无法将其他排序谓词添加到
std::set
。
If you want an additional ordering on your objects that will allow you to achieve O(log N) lookups, you could use another ordered structure that is kept in sync with the original one. 如果您希望对对象进行其他排序以实现O(log N)查找,则可以使用与原始对象保持同步的另一有序结构。 A
std::set
of pointers to objects in the first set that uses a different comparator could work. 一个
std::set
指向第一个使用不同比较器的对象的指针集可以工作。 Example: 例:
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)); }
};
Not with std::set, as @Vittorio Romeo points out in his answer. 不使用std :: set,就像@Vittorio Romeo在他的答案中指出的那样。
There is a boost datastructure that can lookup by unrelated members, which you would define like 有一个可以由不相关成员查找的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.