std::set 使用自定义比较器的操作
std::set operations with custom comparator
我有一个问题。当我将 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) << " ";
}
输出将是:
7 9 6 5 3 8 4 2 1 0
0 0 0 0 0 0 0 0 0 0
如何将 std::set 与自定义比较器一起使用,使所有操作都能正常工作?
提前致谢。
尝试更改
struct comp {
bool operator()(int const & a, int const & b) const {
return sz(a) >= sz(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:
A binary predicate that takes two arguments of the same type as the elements and returns a bool. The expression comp(a,b), where comp is an object of this type and a and b are key values, shall return true if a is considered to go before b in the strict weak ordering the function defines.
你的比较器没有这样做。
关于事物理论方面的更多信息:
根据 documented requirements for std::set
's comparator (and every other "less-than comparator" in the standard library), it needs to establish a strict weak ordering:
- 所有
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
为了简短起见,我省略了不可比性要求的传递性,它由 cppreference 文档中的 equiv
表达式处理,但请注意,以上三个还不够。
您可以将比较视为提问 "Must a
come before b
?" 实施假设这是比较所问的问题,并且对相等元素的回答是否定的,一个不能出现在另一个之前。您的比较器未通过前两个测试:
comp(0,0)
returns true
comp(1,2)
returnstrue
,但是comp(2,1)
returnsfalse
这不是任意的。为简单起见,想象一个朴素的排序数组。您有 3 1
并想要插入 2
。从头开始,您检查 comp(2,1)
。它 returns true
因为两者具有相同的位数,所以你已经完成了,现在你有 2 3 1
。显然,这是不正确的。这并不是说 std::set
与排序数组相同,但它需要 something 来确定放置和查找元素的位置。严格的弱排序使这个过程保持一致。
您真正想要的降序 popcount 排序是严格大于比较。因此,更改是微不足道的:
return sz(a) > sz(b);
我有一个问题。当我将 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) << " ";
}
输出将是:
7 9 6 5 3 8 4 2 1 0
0 0 0 0 0 0 0 0 0 0
如何将 std::set 与自定义比较器一起使用,使所有操作都能正常工作? 提前致谢。
尝试更改
struct comp {
bool operator()(int const & a, int const & b) const {
return sz(a) >= sz(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:
A binary predicate that takes two arguments of the same type as the elements and returns a bool. The expression comp(a,b), where comp is an object of this type and a and b are key values, shall return true if a is considered to go before b in the strict weak ordering the function defines.
你的比较器没有这样做。
关于事物理论方面的更多信息:
根据 documented requirements for std::set
's comparator (and every other "less-than comparator" in the standard library), it needs to establish a strict weak ordering:
- 所有
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
为了简短起见,我省略了不可比性要求的传递性,它由 cppreference 文档中的 equiv
表达式处理,但请注意,以上三个还不够。
您可以将比较视为提问 "Must a
come before b
?" 实施假设这是比较所问的问题,并且对相等元素的回答是否定的,一个不能出现在另一个之前。您的比较器未通过前两个测试:
comp(0,0)
returnstrue
comp(1,2)
returnstrue
,但是comp(2,1)
returnsfalse
这不是任意的。为简单起见,想象一个朴素的排序数组。您有 3 1
并想要插入 2
。从头开始,您检查 comp(2,1)
。它 returns true
因为两者具有相同的位数,所以你已经完成了,现在你有 2 3 1
。显然,这是不正确的。这并不是说 std::set
与排序数组相同,但它需要 something 来确定放置和查找元素的位置。严格的弱排序使这个过程保持一致。
您真正想要的降序 popcount 排序是严格大于比较。因此,更改是微不足道的:
return sz(a) > sz(b);