C++ Stl Set Behavior
C++ Stl Set Behavior
我试图运行下面的代码。我发现输出存在差异。我知道比较器功能中使用的排序机制存在问题。我基本上要找的是:1) Set 如何在内部存储数据。2) 如何解决此问题或将数据复制到其他 Set 的最佳方法。3)排序究竟是如何产生这个问题的。
#include <iostream>
#include <set>
using namespace std;
struct Comparator {
bool operator()( const int& a, const int& b ) {
if( a <= b )
return true;
else
return false;
}
};
int main()
{
set< int, Comparator > customSet;
for( unsigned k = 0, index = 2; k < 10; ++k ) {
customSet.insert( index );
}
set< int, Comparator >::iterator iter = customSet.begin();
for(; iter != customSet.end(); ++iter ) {
cout<<*iter<<endl;
}
cout<<"---------------------------------"<<endl;
set< int, Comparator > tempCustomSet ;//= customSet;
tempCustomSet.insert( customSet.begin(), customSet.end() );
iter = tempCustomSet.begin();
for(; iter != tempCustomSet.end(); ++iter ) {
cout<<*iter<<endl;
}
return 0;
}
1) Set 如何在内部存储数据
唯一的要求是元素是:
- 根据比较器排序,因此如果
Comp(a,b)
,则在迭代集合时a
出现在b
之前; - 独特,因此没有
Comp(a,b)
和Comp(b,a)
都成立的独特元素。
并且操作满足某些复杂性要求。
实际上,它们通常存储在二叉搜索树中;但这对用户来说并不重要。
2) 如何解决此问题或将数据复制到其他集合的最佳方法
为了满足要求,比较器必须是像<
那样的严格弱排序,这样Comp(a,a)
总是假的,而不是像<=
那样的非严格排序。由于<
是默认值,这意味着您根本不需要自定义比较器。
3)订单究竟是如何产生这个问题的
请注意,您的第一个循环是插入值2
十次;我不确定这是否是意图。
给定所需的严格排序,insert(b)
可能会通过查找第一个元素来寻找插入点a
,以便Comp(a,b)
为假;即b
不应该在后面的第一个元素。然后,它将通过检查Comp(b,a)
来检查唯一性。如果两者都为 false,则表示这两个值是等效的,因此不会插入b
。
由于您的比较并不严格,因此此唯一性测试可能会失败;因此您最终可能会得到重复的条目。或者可能会发生其他事情 - 行为未定义。
std::set
的更多详细信息,请参阅此参考。实现不应该与你有关(它们可能因平台而异),因为接口和复杂性保证对标准来说才是最重要的。典型的实现是使用红黑树。
你需要让你的Comparator
使用operator<
而不是operator<=
。原因是,如果!Comparator(a, b) && !Comparator(b, a)
计算结果为 true
,std::set
会认为元素等价(即两者都严格小于另一个)。
但是有了<=
,你有a <= a
等于true
,所以!(a<=a) && !(a<=a)
给相等元素false
。而有了<
,你a < a
等于false
所以!(a<a) && !(a<a)
true
.
做事的权利是:
struct Comparator
{
bool operator()(int const& lhs, int const& rhs) const
{
return lhs < rhs;
}
};
这将保证相等的元素被视为等效的。请注意,有效STL中详细讨论了这个问题,"项目19.了解平等和等价之间的区别。
问题很可能是因为您的比较没有实现严格的弱排序。集合上的内部排序机制依赖于此。您可以通过将比较更改为小于:
struct Comparator {
bool operator()( const int& a, const int& b ) const {
return ( a < b );
}
};
另一方面,默认情况下,std::set
将使用此比较条件,因此您无需指定它。
在我对这个问题的回答中有一些相关信息(以及其他无数个SO问题)。
在两种情况下,您会得到不同的输出,因为您inserting in different ways
.在情况 1 中,您将插入元素 2 十次。在这种情况下,当您在第一次插入整数 2 后,将调用您的 Comparator()
函数来决定插入的位置。在另一种情况下,您正在插入一个范围。在这里,调用函数接受第一个参数,即customSet.begin()
,并将其与另一个参数 i,e customSet.end()
进行检查,如果这两个参数不相等,则只插入一个元素,否则不会插入元素。
- 为什么我无法更改"set<set>"循环中的值<int>
- 对于set上的循环-获取next元素迭代器
- 在声明中合并两个常量"std::set"(不是在运行时)
- 有没有办法对std::unordered_set、std::unrdered_map、std::set、std::map
- 将 std::set 与基于键的比较器一起使用
- 如何使用set实现无序数据结构?
- 使用运算符调用 void 函数时出错<set>
- 修改"std::set"中用户定义类型的值
- 生成提升::hana::set 的常量表达式问题
- 如何在构造函数参数中初始化"std::set"?
- 如何使用 lower_bound/upper_bound 从 std::set 获取索引号?
- 如何在 C++ 中转发声明 std::set?
- 重构使用动态强制转换的 std::set 的比较运算符
- set::find 查找不存在的元素
- 为什么 std::set.erase(first, last) 会影响从中获取 (first, last) 的容器?
- 将 std:set<int32_t> 复制到 std::set <uint32_t>的好方法
- 错误 C2676:std::set::const_iterator 没有运算符 + 函数?
- std::set 是否将对象连续存储在内存中?
- 是否有一个 std::set 函数来确定不超过数字 x 的最大元素?
- C++ Stl Set Behavior