C++ std::set 使用自定义lower_bound
C++ std::set with a custom lower_bound
如何使用独立于其键的比较器函数在std::set
上执行find()
或lower_bound()
函数,使其仍然在O(log N)时间内运行?
假设我定义了一个数据类型foo
,其中包含两个变量x
和y
,并且有一个使用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
值的函数执行二分搜索?
为了这个论证,假设x
和y
是唯一的并且彼此独立,并且给定两个foo
变量foo1
和foo2
,如果foo1.x < foo2.x
,则foo1.y < foo2.y
。这意味着我不能将y
表示为x
的函数,而是在fooSetX
内按y
排序。
例如,给定fooSet
内的三个foo(x,y)
值(2,5),(3,9)和(5,10),一个以y = 7
作为搜索词的lower_bound()
将返回一个指向(3,9)的迭代器。
目前,我解决这个问题的方法是有两个std::set<foo>
,分别按x
和y
排序。每当我需要按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罗密欧在他的回答中指出的那样。
有一个提升数据结构可以按不相关的成员查找,您可以像这样定义
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);
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 如何将点击的信号和插槽添加到qt中的自定义按钮中
- C++自定义比较函数
- 如何比较自定义类的std::变体
- std::设置自定义比较器
- 如何正确实现和访问运算符的各种自定义枚举器
- flutter:即使shouldRepaint()返回true,自定义画家也不会重新绘制
- 自定义先决条件对移动分配运算符有效吗
- 使用VS Code和CMake Tools运行自定义命令
- 如何创建从Maya(或类似程序)到虚幻引擎的自定义数据导出插件
- std::ranges::elements_view,用于自定义类似元组的数据
- 跟随整数索引列表的自定义类迭代器
- 参数化自定义CMake工具链
- 使用自定义比较函数使用std::sort()对矢量字符串进行排序时出现问题
- 如何在自定义类中启用'auto loops'?
- 使用QJsEngine在Qt中注册自定义类型
- Qt自定义QPush按钮未显示在布局上
- 自定义对象的dlib序列化在gcc中失败
- 自定义创建QFuture
- 如何在QT中的自定义视频小工具t上绘制矩形