我有一个定义了自定义排序的C ++ STL集。
这个想法是,当项目被添加到集合中时,它们会按照我的要求自然排序。
但是,我刚刚意识到,排序谓词可以随着时间的推移而改变。
据推测,集合中的项目将不再有序。
真的有两个问题:
这些物品会出现故障是否有害?我是否正确地说,可能发生的最坏情况是新条目可能被放入错误的地方(实际上我可以忍受)。或者,这会导致崩溃,丢失条目等吗?
有没有办法“刷新”套装的顺序?您似乎无法在集合上使用std :: sort()。我能想到的最好的方法是将内容转储到临时容器中并重新添加。
有什么想法吗?
谢谢,
约翰
答案 0 :(得分:7)
set
使用排序来查找项目。如果您根据ordering1插入N个项目并根据orders2插入项目,则该集合无法确定该项目是否已经存在。
它会违反每个项目只存在一次的类不变量。
所以它 伤害。
答案 1 :(得分:4)
使用STL执行此操作的唯一安全方法是使用更改的谓词创建新集。例如,当您需要使用新谓词对集合进行排序时,您可以执行类似的操作:
std::set<int> newset( oldset.begin(), oldset.end(), NewPred() );
答案 2 :(得分:2)
这实际上取决于实施 STL实现可以并且通常假定用于排序的谓词是稳定的(否则,“排序”将不被定义)。至少可以构建一个有效的STL实现,在您更改谓词实例的行为时格式化硬盘驱动器。
所以,是的,你需要将这些项重新插入一个新的集合中。
或者,您可以构建自己的容器,例如二进制搜索的向量+ sort + lower_bound。然后,您可以在谓词行为发生变化时重新排序。
答案 3 :(得分:2)
我同意其他答案,这将在一些奇怪且难以调试的方式中突破。如果你去刷新路线,你只需要复制一次。使用新的排序策略创建tmp集,将原始集中的每个元素添加到tmp集,然后执行
orig.swap(tmp);
这将交换集合的内部。
如果这是我,我会将其包装在一个处理所有细节的新类中,以便您可以根据需要更改实现。根据您的访问模式和排序顺序更改的次数,前面提到的矢量,排序,下限解决方案可能更合适。
答案 4 :(得分:2)
如果您可以使用无序集合,那么为什么要将它们添加到集合中呢?
我能想到的唯一情况是,您只想在添加列表时确保列表是唯一的。如果是这种情况,那么您可以使用临时集来保护添加内容:
if (ts.insert (value).second) {
// insertion took place
realContainer.push_back (value);
}
另一种方法是,根据您修改集合中条目的频率,您可以测试以查看条目是否位于不同的位置(通过使用设置比较功能)和位置将移动然后删除旧条目并重新添加新条目。
正如其他人所指出的那样 - 让无序的集合真的闻起来很糟糕 - 我也猜测它可能会根据标准获得未定义的行为。
答案 5 :(得分:2)
虽然这并不能完全满足您的需求,但boost::multi_index为您提供了类似的功能。由于模板的工作方式,您永远无法“更改”容器的排序谓词,它在编译时设置为一块石头,除非您使用排序的矢量或类似的东西, you < / em>是维护不变量的那个,你可以在任何给定的时间对它进行排序。
然而,Multi_index为您提供了一种基于多个排序谓词同时对一组元素进行排序的方法。然后,您可以选择容器的视图,其行为类似于您当时关注的谓词所排序的std :: set。
答案 6 :(得分:1)
这会导致丢失条目,当在set
中搜索元素时,使用了排序运算符这意味着如果元素放在根的左边,现在排序操作符说它在右边然后将找不到该元素。
答案 7 :(得分:0)
这是一个简单的测试:
struct comparer : public std::binary_function<int, int, bool>
{
static enum CompareType {CT_LESS, CT_GREATER} CompareMode;
bool operator()(int lhs, int rhs) const
{
if(CompareMode == CT_LESS)
{
return lhs < rhs;
}
else
{
return lhs > rhs;
}
}
};
comparer::CompareType comparer::CompareMode = comparer::CT_LESS;
typedef std::set<int, comparer> is_compare_t;
void check(const is_compare_t &is, int v)
{
is_compare_t::const_iterator it = is.find(v);
if(it != is.end())
{
std::cout << "HAS " << v << std::endl;
}
else
{
std::cout << "ERROR NO " << v << std::endl;
}
}
int main()
{
is_compare_t is;
is.insert(20);
is.insert(5);
check(is, 5);
comparer::CompareMode = comparer::CT_GREATER;
check(is, 5);
is.insert(27);
check(is, 27);
comparer::CompareMode = comparer::CT_LESS;
check(is, 5);
check(is, 27);
return 0;
}
所以,基本上如果您打算能够找到您插入的元素,则不应更改用于插入和查找的谓词。
答案 8 :(得分:0)
只是跟进:
运行此代码时,Visual Studio C调试库开始抛出异常,抱怨“&lt;”运营商无效。
所以,似乎改变排序顺序似乎是件坏事。谢谢大家!
答案 9 :(得分:-3)
1)有害 - 没有。导致崩溃 - 没有。最糟糕的确是一个未排序的集合。
2)“刷新”与重新添加相同!