【问题标题】:Using lower_bound, upper_bound, and binary_search to find the object with an equal member field使用 lower_bound、upper_bound 和 binary_search 查找具有相等成员字段的对象
【发布时间】:2012-11-01 12:24:03
【问题描述】:

我有一个看起来像这样的结构,

struct Foo {
    int a;
};

我有一个由这些结构组成的向量,看起来像这样,

vector<Foo> foos;

所有Foos 都使用STL sort() 函数按整数a 升序排序。现在我想获取成员字段a 小于或等于给定数字的Foo 对象,例如STL lower_bound() 函数。问题是 STL 的 lower_bound 函数声明如下所示:

template <class ForwardIterator, class T, class Compare>
  ForwardIterator lower_bound ( ForwardIterator first, ForwardIterator last,
                                const T& value, Compare comp );

所以当我想做类似的事情时,

lower_bound(foos.begin(), foos.end(), 5, custom_comp);

我不能,因为我正在寻找的 int(在本例中为 5)不是 Foo 类型。我遇到了lower_bound()、upper_bound() 和binary_search() 的问题。 custom_comp 只定义了排序,并没有定义 a = 5 的对象实际上等于 int 5。

STL 有什么优雅的方法吗?

编辑:

我意识到我的例子并不能完全代表我的问题。我实际上拥有的是 Foo 包含两个整数,a 和 b。当我调用 lower_bound 时,我无权访问 b(因为我不在乎它)。现在 billz 答案的问题是我必须定义一个只接受 a 作为参数的构造函数,这在我看来不是很优雅(因为 b 未定义或任意,并且可以使用此构造函数代码中的任何位置)。但如果这是唯一的选择,我会接受。

【问题讨论】:

  • 在 [stackoverflow.com/questions/5072257/… 中有更好的解决方案,这个问题可能与该问题重复。总结:在lower_bound模板中,类T不一定是两个迭代器[first,last)范围内的容器内容的数据类型。这意味着,T 可以只是一个要比较的整数。你可以把比较器写成bool Compare(Foo &amp; f, int value) { return f.a &lt; value; }。它从 C++03 开始​​工作。

标签: c++ search stl


【解决方案1】:

你可以为你的 struct Foo 提供一个构造函数

struct Foo {
  Foo(int x):a(x){
  }
    int a;
};

您现在可以调用:

std::lower_bound(foos.begin(), foos.end(), 5, custom_comp);

std::lower_bound(foos.begin(), foos.end(), Foo(5), custom_comp);

Foo f(5);
std::lower_bound(foos.begin(), foos.end(), f, custom_comp);

建议的方式是:

struct Foo {
  explicit Foo(int x):a(x){
  }
    int a;
};

std::lower_bound(foos.begin(), foos.end(), Foo(5), custom_comp);

【讨论】:

  • 然后我需要为 Foo 定义一个 operator== 吗?
  • @gsingh2011 不,operator&lt;,但前提是你不使用 custom_comp,它会做同样的事情。
  • 有时隐式转换很痛苦
  • 问题 1:只有int 状态的Foo 可能不是有效的Foo。问题 2:Foo 的制作成本可能很高。问题 3:您正在破解数据结构,因此您可以在数据结构上运行一些不需要对数据结构进行任何破解的算法。
  • @Yakk-AdamNevraumont 的反对意见是有效的。 This答案提供了更好的解决方案
【解决方案2】:

在 C++11 中,您可以使用以下内容:

std::lower_bound(foos.begin(), foos.end(), Foo{5},
    [](const Foo& f1, const Foo& f2) { return f1.a < f2.a; });

或者在 C++03 中:

Foo f = {5};
std::lower_bound(foos.begin(), foos.end(), f, custom_comp);

【讨论】:

    【解决方案3】:

    让您的 custom_comp 同时接受 fooint 作为参数。这意味着它要么需要是一个仿函数,要么可以采用 foo_sort_helper 参数(可以从 intfoo 构造)并对它们进行排序。

    或者,明确地说:

    struct FooSortHelper
    {
      int ordering;
      FooSortHelper( Foo const& foo ):ordering(foo.value) {}
      FooSortHelper( int i ): ordering(i) {}
      FooSortHelper( FooSortHelper const& other):ordering(other.ordering) {}
      bool operator<( FooSortHelper const& other ) { return ordering < other.ordering }
    };
    
    auto lower = std::lower_bound( vec.begin(), vec.end(), 5,
      []( FooSortHelper left, FooSortHelper right ) {
        return left < right;
      }
    );
    

    你看到我是如何封装FooFooSortHelper 中排序的吗?通过允许从 int 构造它,我允许 Fooint 无缝比较。

    我提到的替代方法是创建一个在每对 Fooint(全部 4 个)上重载 operator() 的类。我发现上面的更容易。

    如果您要排序的类型复制成本很高(例如std::string),FooSortHelper 可以存储对所述字段的引用。

    【讨论】:

    • 但 lower_bound 会尝试将 Foo 传递给 custom_comp...它不知道将 int 传递给 Foo。
    • 没错。所以custom_comp 需要Foos 和ints。这需要一个仿函数struct custom_comp { bool operator()(int, Foo const&amp;) const; bool operator()(Foo const&amp;, int) const; bool operator()(int, int) const; bool operator()(Foo const&amp;, Foo const&amp;) const; };,我觉得这很烦人,或者需要上面的辅助技巧。帮助器可以由Fooint 构造,并且仅存储Foo 中排序所需的部分。我是用 lambda 做的,但如果你愿意,你可以使用 custom_comp 函数或仿函数。
    猜你喜欢
    • 2021-03-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-26
    相关资源
    最近更新 更多