2014-11-23 43 views
2

假设存储元素的容器(在这种情况下,一个普通数组)就像二进制搜索等效`find_if`

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

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

+0

为'find_if'接口是无用的二分查找。如果这是一场比赛,那很好。但是如果谓词表示它不匹配,那么搜索应该在下一个当前点之前还是之后查找? – 2014-11-23 20:51:45

+0

还有一个明智的方向吗?假设条件是'isPrime(int x)',第一个值'x'是100.现在呢? – MSalters 2014-11-24 11:12:32

+0

也许接口不完全一样,但返回一个int指示方向。 – user877329 2014-11-24 11:18:13

回答

6

您在寻找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()) 
+0

使用'id + strlen(id)'作为lexicographical_compare的第二个参数可能更安全。但+1的一个很好的答案 – Fiktik 2014-11-23 20:56:50

+0

@Fiktik:它也慢。我想过把参数声明为const char(&id)[8]'。如果需要任意以空字符结尾的字符串,最好实现您自己的单遍算法。 – 2014-11-23 21:14:33

+0

@KerrekSB我只想看看字符串的开头,所以这种方法并不能完全解决问题。 – user877329 2014-11-24 16:14:46