C++ std::使用自定义比较器设置操作

C++ std::使用自定义比较器设置操作,c++,c++11,std,stdset,C++,C++11,Std,Stdset,我有个问题。当我使用带有自定义比较器的std::set时,其他操作(如擦除或计数)无法正常工作。 例如: int sz(int const & n) { return __builtin_popcount(n); } struct comp { bool operator()(int const & a, int const & b) const { return sz(a) >= sz(b); } }; void solve() { s

我有个问题。当我使用带有自定义比较器的std::set时,其他操作(如擦除或计数)无法正常工作。 例如:

int sz(int const & n) {
  return __builtin_popcount(n);
}

struct comp {
  bool operator()(int const & a, int const & b) const {
    return sz(a) >= sz(b);
  }
};

void solve() {
  set<int, comp> s;

  for (int i = 0; i < 10; ++i)
    s.insert(i);

  for (int x : s)
    cerr << x << " ";

  cerr << "\n";

  for (int i = 0; i < 10; ++i)
    cerr << s.count(i) << " ";
}
如何将std::set与自定义比较器一起使用,以确保所有操作都能正常工作? 提前谢谢。

试试换衣服

struct comp {
  bool operator()(int const & a, int const & b) const {
    return sz(a) >= sz(b);
  }
};

第一个问题是,比较器必须施加严格的弱排序

因此,特别是对于
std::set
中的每个
a
,必须是
comp(a,a)=false

使用比较器,每个
a
都有
comp(a,a)=true

无论如何:仅当
a!=b
s(a)!=s(b)
;如果不是这样的话。。。好。。。我想你可以试试这个

struct comp {
  bool operator()(int const & a, int const & b) const {
    return (sz(a) > sz(b)) || ((sz(a) == sz(b)) && (a > b));
  }
};
或者类似的东西。

试着改变一下

struct comp {
  bool operator()(int const & a, int const & b) const {
    return sz(a) >= sz(b);
  }
};

第一个问题是,比较器必须施加严格的弱排序

因此,特别是对于
std::set
中的每个
a
,必须是
comp(a,a)=false

使用比较器,每个
a
都有
comp(a,a)=true

无论如何:仅当
a!=b
s(a)!=s(b)
;如果不是这样的话。。。好。。。我想你可以试试这个

struct comp {
  bool operator()(int const & a, int const & b) const {
    return (sz(a) > sz(b)) || ((sz(a) == sz(b)) && (a > b));
  }
};

或者类似的东西。

根据cppreference.com:

一种二进制谓词,它接受两个与元素类型相同的参数并返回布尔值。表达式comp(a,b),其中comp是此类型的对象,a和b是键值,如果在函数定义的严格弱顺序中a被认为在b之前,则应返回true


您的比较器不会这样做。

根据cppreference.com:

一种二进制谓词,它接受两个与元素类型相同的参数并返回布尔值。表达式comp(a,b),其中comp是此类型的对象,a和b是键值,如果在函数定义的严格弱顺序中a被认为在b之前,则应返回true


您的比较器不会这样做。

更多关于理论方面的内容:

根据for
std::set
的比较器(以及标准库中每隔一个“小于比较器”),它需要建立一个:

  • 对于所有
    a
    comp(a,a)=false
  • 如果
    comp(a,b)==true
    comp(b,a)==false
  • 如果
    comp(a,b)==true
    comp(b,c)==true
    comp(a,c)==true
简而言之,我省略了不可比较性需求的传递性,这是由CPPPreference文档中的
equiv
表达式处理的,但请注意,以上三个还不够

您可以将比较视为询问“必须
a
b
之前出现?”实现假设这是比较所询问的问题,对于相等元素的回答是否,一个元素不得出现在另一个元素之前。您的比较器未通过前两项测试:

  • comp(0,0)
    返回
    true
  • comp(1,2)
    返回
    true
    ,但
    comp(2,1)
    返回
    false
这不是武断的。为简单起见,请想象一个简单的排序数组。您有
3 1
并希望插入
2
。从开头开始,您检查
comp(2,1)
。它返回
true
,因为两者的位数相同,所以您完成了,现在您有了
2 3 1
。显然,这是错误的。这并不是说
std::set
与排序数组相同,但在确定元素的放置和查找位置时,它需要进行一些操作。严格的弱排序使该过程保持一致

对于递减的popcount排序,您真正想要的是严格意义上的大于比较。因此,变化是微不足道的:

return sz(a) > sz(b);

更多关于理论方面的内容:

根据for
std::set
的比较器(以及标准库中每隔一个“小于比较器”),它需要建立一个:

  • 对于所有
    a
    comp(a,a)=false
  • 如果
    comp(a,b)==true
    comp(b,a)==false
  • 如果
    comp(a,b)==true
    comp(b,c)==true
    comp(a,c)==true
简而言之,我省略了不可比较性需求的传递性,这是由CPPPreference文档中的
equiv
表达式处理的,但请注意,以上三个还不够

您可以将比较视为询问“必须
a
b
之前出现?”实现假设这是比较所询问的问题,对于相等元素的回答是否,一个元素不得出现在另一个元素之前。您的比较器未通过前两项测试:

  • comp(0,0)
    返回
    true
  • comp(1,2)
    返回
    true
    ,但
    comp(2,1)
    返回
    false
这不是武断的。为简单起见,请想象一个简单的排序数组。您有
3 1
并希望插入
2
。从开头开始,您检查
comp(2,1)
。它返回
true
,因为两者的位数相同,所以您完成了,现在您有了
2 3 1
。显然,这是错误的。这并不是说
std::set
与排序数组相同,但在确定元素的放置和查找位置时,它需要进行一些操作。严格的弱排序使该过程保持一致

对于递减的popcount排序,您真正想要的是严格意义上的大于比较。因此,变化是微不足道的:

return sz(a) > sz(b);

您的比较器没有严格的弱排序<代码>cmp(a,b)意味着
!cmp(b,a)
,但如果
sz(a)=sz(b)
,则您的比较器将为这两个值返回true。甚至