Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/135.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么使用std::less作为默认函子来比较std::map和std::set中的键?_C++_Stdmap_Stdset - Fatal编程技术网

C++ 为什么使用std::less作为默认函子来比较std::map和std::set中的键?

C++ 为什么使用std::less作为默认函子来比较std::map和std::set中的键?,c++,stdmap,stdset,C++,Stdmap,Stdset,我想知道为什么std::map和std::set使用std::less作为比较键的默认函子。为什么不使用类似strcmp的函子呢?比如: template <typename T> struct compare { // Return less than 0 if lhs < rhs // Return 0 if lhs == rhs // Return greater than 0 if lhs > rhs int ope

我想知道为什么
std::map
std::set
使用
std::less
作为比较键的默认函子。为什么不使用类似strcmp的函子呢?比如:

  template <typename T> struct compare
  {
     // Return less than 0 if lhs < rhs
     // Return 0 if lhs == rhs
     // Return greater than 0 if lhs > rhs
     int operator()(T const& lhs, T const& rhs)
     {
        return (lhs-rhs);
     }
  }
模板结构比较
{
//如果lhsrhs,返回值大于0
int运算符()(T常量和lhs、T常量和rhs)
{
返回(左侧和右侧);
}
}
假设
map
中有两个对象,其中包含键
key1
key2
。现在,我们要插入另一个具有键
key3
的对象

使用
std::less
时,
insert
函数需要首先使用
key1
key3
调用
std::less::operator()
。假设
std::less::operator()(键1,键3)
返回false。它必须在切换键的情况下再次调用
std::less::operator()
std::less::operator()(key3,key1)
,以确定
key1
是否等于
key3
key3
大于
key1
。有两个调用std::less::operator()来决定第一个调用是否返回false

如果使用了
std::map::insert
compare
,那么只需一次调用就有足够的信息来做出正确的决策

根据映射中键的类型,
std::less::operator()


除非我缺少一些非常基本的东西,否则
std::map
std::set
不应该使用类似
compare
的东西,而不是
std::less
作为比较键的默认函数吗?

基于树的容器只需要严格的弱总排序

  • 写访问

    地图和集合的插入点完全由单个二进制搜索确定,例如
    下限
    上限
    。二进制搜索的运行时复杂性是
    O(logn)

  • 读访问

    同样的道理也适用于搜索:搜索比线性相等扫描的效率要高得多,这正是因为大多数元素不需要进行比较。诀窍在于容器是有序的


  • 结果是
    平等性
    信息不需要存在。只是,项目可以具有同等的顺序


    在实践中,这仅仅意味着对元素类型的约束更少,在常见使用场景中实现需求和最佳性能的工作量更少。总会有取舍。(例如,对于大型集合,哈希表(无序集和映射)通常效率更高。请注意,这些确实需要
    相等的
    元素,并且它们采用哈希方案进行快速查找)

    我决定向Alexander Stepanov(STL的设计师)询问这一点。我可以引用他的话如下:

    最初,我提出了三方比较。标准委员会问道 我将更改为标准比较运算符。我照吩咐的做了。 我一直主张将3向组件添加到 20多年了

    但请注意,也许不直观地说,双向并不是一个巨大的开销。你不必做两倍的比较。在下降过程中,每个节点仅进行一次比较(无相等检查)。代价是不能提前返回(当键在非叶中时)并在最后进行一次额外的比较(交换参数以检查相等性)。如果我没弄错的话,那就是

    1 + 1/2*1 + 1/4*2 + 1/8*3 + ...
    = 1 + 1/2+1/4+1/8+... + 1/4+1/8+... + ...
    -> 3  (depth -> infty)
    
    在包含查询元素的平衡树上平均进行额外比较

    另一方面,三方比较没有可怕的开销:。现在,另一个问题是,在每个节点上用一个额外的分支来检查与0(相等)的比较结果是否比在最后额外进行3次比较的开销小。可能没什么大不了的。但我认为比较本身应该是三值的,这样是否使用所有三种结果的决定就可以改变


    更新:请参阅下面的评论,了解为什么我认为三向比较在树中更好,但在平面阵列中不一定更好。

    不是
    std::set
    std::map
    都是隐藏的RB树吗?但这意味着对于希望使用映射或映射的任何数据类型,都必须重载
    -
    操作符set@Smac89,这是真的。同样正确的是,您必须实现
    operator@Paranaix我认为这在技术上是一个实施细节。但是,如果您深入到标准规范的底部,您可能会发现很难找到另一个仍然满足标准指定的性能约束的实现。@在AIX中,标准不要求任何特定的结构,只要求性能保证。返回
    <0
    <0的比较函数,
    ==0
    >0
    可用于任何小于
    的比较函数,只要返回
    0
    (如果
    )!减去(a,b)&!减去(b,a)
    。它同样具有表现力,没有任何类型可以有可用的
    less
    函数,但没有可用的
    compare
    函数。@hvd这是重言式。然而,在实践中,
    操作符=
    通常用于表示相等语义,而不是等价。将两者混合在一起将是非常令人惊讶的。并非所有具有总排序的类型都必须实现相等。是的,您是对的,我已经编辑了以前的注释以删除对
    operator==
    的引用。但是比较两个项目并根据比较结果返回负、零或正的函数已经被广泛使用,其中零并不意味着相等。一个非常常见的例子是不区分大小写的字符串比较。很好的一点,@hvd。你说得对。这是一个
    比较