【问题标题】:Discrepencies between std::lower_bound and std::set::lower_boundstd::lower_bound 和 std::set::lower_bound 之间的差异
【发布时间】:2011-11-21 06:42:57
【问题描述】:

C++ 草案中提到了 std::lower_bound:

§ 25.4.3.1 lower_bound [lower.bound]  
template<class ForwardIterator, class T>  
ForwardIterator lower_bound(ForwardIterator first, 
                            ForwardIterator last, 
                            const T& value);  
template<class ForwardIterator, class T, class Compare>  
ForwardIterator lower_bound(ForwardIterator first, 
                            ForwardIterator last, 
                            const T& value, 
                            Compare comp);  

Requires: The elements e of [first,last) shall be partitioned with respect 
    to the expression e < value or comp(e, value).
Returns: The furthermost iterator i in the range [first,last] such that for 
    any iterator j in the range [first,i) the following corresponding 
    conditions hold: *j < value or comp(*j, value) != false.
Complexity: At most log2(last − first) + O(1) comparisons.

请注意,这允许(通过暗示)比较与 *ForwardIterator 将返回的不同(但可比较)类型,但对迭代器改进的数​​量没有复杂性限制。 (对于基于节点的容器,这将是 O(last − first) 迭代器进度。)

§ 23.4.6.1
class set { 
   ...
    iterator lower_bound(const key_type& x);
    const_iterator lower_bound(const key_type& x) const;
   ...
}

标准没有详细说明这些函数,但暗示这些函数用于 O(log2(last − first)) 比较和改进,但要求搜索键与包含的类型相同。

所以我的问题是:
(1)有没有办法获得std::set::lower_bound的速度和std::lower_bound的搜索类型的灵活性?
(2) 为什么std::lower_bound不需要专门化为std::set::iterator
(3) 是否有std::lower_bound 专门用于std::set::iterator 的实现,或者有什么理由不这样做?

我希望找到类似的东西:

template< class Key, class Comp, class Alloc, class Lookup>  
std::set<Key, Compare, Alloc>::const_iterator 
    lower_bound(
        std::set<Key, Comp, Alloc>::const_iterator begin, 
        std::set<Key, Comp, Alloc>::const_iterator end, 
        const Lookup& find,
        Compare comp);
template< class Key, class Comp, class Alloc, class Lookup>  
std::set<Key, Compare, Alloc>::iterator 
    lower_bound(
        std::set<Key, Comp, Alloc>::iterator begin, 
        std::set<Key, Comp, Alloc>::iterator end, 
        const Lookup& find,
        Compare comp);

或:

template < class Key, class Compare = less<Key>, class Allocator = allocator<Key> >
class set {
   ...
    template<class Lookup>
    iterator lower_bound(const Lookup& x);
    template<class Lookup>
    const_iterator lower_bound(const Lookup& x) const;
   ...
}

但我怀疑它的存在。显然,所有这些都可以扩展到其他基于树的容器和其他算法。我会自己编写代码,但这需要我使用特定于实现的代码。这个想法来自这个问题:Efective search in set with non-key type

【问题讨论】:

  • Note N3657(2013-04 采用)向关联容器添加了异构比较查找,这是 C++14 的一部分。不过,它仍然需要等效密钥。

标签: c++ stl tree set lower-bound


【解决方案1】:

std::set 容器根据构造时给出的比较对象进行排序。当std::lower_bound 被调用时,没有办法检查它是否传递了一个匹配的比较对象,因此实现无法知道是使用标准算法还是专门用于集合的算法,因为后者仅在使用时有效用于集合排序的比较对象(或给出相同结果的对象)。

您添加的两个示例原型不起作用:

  1. 专门化 std::lower_bound 来处理 std::set 迭代器:

    由于上述原因,这将不起作用:无法检查给定的比较对象是否与集合构造函数中给定的比较对象匹配。你的原型只检查比较对象的类型是否匹配,但同一类型可以有不同的比较对象。

  2. 使std::set::lower_bound 接受模板参数:

    这可能使其与集合的比较对象不兼容,因为该对象的 operator() 通常不会被模板化,并且只需要 T 类型的参数。

【讨论】:

  • 想出一个可以避免这个问题的概念和原型并不复杂。我在问题中添加了原型。
  • @Mooing:您添加的原型与标准 std::lower_bound 的行为不同,因为它使用集合的比较器,而 std::lower_bound 的 3 参数版本使用 operator&lt;。这使得它与标准不兼容。
  • 这很容易解决。现在原型只有在他们给出正确的比较对象时才会起作用。
  • 已接受。尽管如果 std::less 也采用了两种模板类型,则可以部分绕过该问题……这保留了几乎所有现有功能(包括编译器错误),但也允许比较不同的类型。
猜你喜欢
  • 2015-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-26
  • 1970-01-01
  • 2012-02-05
  • 1970-01-01
  • 2017-08-30
相关资源
最近更新 更多