【问题标题】:Binary search equivalent for `find_if``find_if` 的二进制搜索等效项
【发布时间】:2014-11-23 20:40:51
【问题描述】:

假设一个容器(在本例中是一个普通数组)存储类似的元素

struct Foo
    {
    char id[8];
    // other members
    };

现在我想找到一个Foo,其 id 以特定字符串 S 开头。由于数组是按id排序的,所以我想使用二进制搜索,所以我寻找一个与find_if具有相同接口的执行二进制搜索的函数。 STL中是否有这样的功能,是否可以使用algorithm中的其他元素来构造,还是需要我自己实现。

【问题讨论】:

  • find_if 的接口对于二分查找是没用的。如果是比赛,那就太好了。但是如果谓词说它不匹配,那么搜索应该在当前点之前还是之后寻找呢?
  • 还有明智的方向吗?假设条件是isPrime(int x),第一个值x 是100。现在呢?
  • 可能不是完全相同的接口,而是返回一个int指示方向。

标签: c++ stl stl-algorithm


【解决方案1】:

您正在寻找std::lower_boundstd::upper_boundstd::equal_range,它们接受输入范围、搜索值和可选比较器,并要求根据比较器对范围进行排序。

对于您的具体示例,我将使用 std::lexicographical_compare 作为比较器:

#include <algorithm>
#include <iterator>

struct IdCmp
{
  bool operator()(const Foo & lhs, const Foo & rhs) const
  {
    return std::lexicographical_compare(std::begin(lhs.id), std::end(lhs.id),
                                        std::begin(rhs.id), std::end(rhs.id));
  }
};

int main()
{
  Foo a[100];           // populate
  Foo b = make_needle();

  auto p = std::equal_range(std::begin(a), std::end(a), b, IdCmp());

  /* The elements with key equal to that of b are in [p.first, p.second). */
}

如果您希望能够直接搜索字符串,您的比较器需要可以通过一个Foo 参数和一个字符串参数进行异构调用。例如:

struct IdCmp
{
  bool operator()(const Foo & lhs, const Foo & rhs) const
  {
    return std::lexicographical_compare(std::begin(lhs.id), std::end(lhs.id),
                                        std::begin(rhs.id), std::end(rhs.id));
  }

  bool operator()(const Foo & lhs, const char * id) const
  {
    return std::lexicographical_compare(std::begin(lhs.id), std::end(lhs.id),
                                        id, id + 8);
  }

  bool operator()(const char * id, const Foo & rhs) const
  {
    return std::lexicographical_compare(id, id + 8,
                                        std::begin(rhs.id), std::end(rhs.id));
  }
};

现在你可以搜索了:

std::lower_bound(std::begin(a), std::end(a), "ABCD1234", IdCmp())

【讨论】:

  • 使用id + strlen(id) 作为lexicographical_compare 的第二个参数可能更安全。但是 +1 是一个很好的答案
  • @Fiktik:它也更慢。我想过将参数声明为const char (&amp;id)[8]。如果需要任意以 null 结尾的字符串,最好实现自己的单遍算法。
  • @KerrekSB 我只想查看字符串的开头,所以这种方法并不能完全解决问题。
【解决方案2】:

我相信您正在寻找std::binary_searchstd::lower_bound

【讨论】:

    猜你喜欢
    • 2012-05-18
    • 2010-10-28
    • 1970-01-01
    • 1970-01-01
    • 2018-12-26
    • 1970-01-01
    • 2014-07-10
    • 2014-03-22
    • 1970-01-01
    相关资源
    最近更新 更多