STL排序集,其中的排序条件可能会发生变化
STL sorted set where the conditions of order may change
我有一个定义了自定义顺序的C++STL集。
当时的想法是,当项目被添加到集合中时,它们会自然地按照我的意愿进行订购。
然而,我刚刚意识到,排序谓词可以随着时间的推移而改变
据推测,集合中的项目将不再按顺序排列。
所以有两个问题:
-
这些物品会出现故障,这有害吗?我说得对吗?最糟糕的情况是,新的参赛作品可能会被放错地方(实际上我可以接受)。或者,这会导致崩溃、条目丢失等?
-
有没有办法"刷新"套装的顺序?您似乎不能在集合上使用std::sort()。我能想到的最好的办法就是把里面的东西倒到一个临时容器里,然后重新添加。
有什么想法吗?
谢谢,
John
set
使用排序来查找项目。如果您要根据ordering1插入N个项目,并根据ordering2插入一个项目,则集合无法确定该项目是否已在。
它将违反类不变量,即每个项只在其中一次。
所以它有危害。
使用STL执行此操作的唯一安全方法是使用更改的谓词创建一个新集合。例如,当你需要用一个新的谓词对集合进行排序时,你可以这样做:
std::set<int> newset( oldset.begin(), oldset.end(), NewPred() );
这实际上取决于实现
STL实现可以而且通常会假设用于排序的谓词是稳定的(否则,将不会定义"已排序")。当您更改谓词实例的行为时,至少可以构造一个有效的STL实现来格式化您的硬盘驱动器。
因此,是的,您需要将这些项目重新插入到一个新的集合中。
或者,您可以构建自己的容器,例如用于二进制搜索的向量+排序+下限。然后,您可以在谓词行为发生变化时重新排序。
我同意其他答案,即这将以一些奇怪且难以调试的方式中断。如果采用刷新路线,则只需要执行一次复制。使用新的排序策略创建一个tmp集合,将原始集合中的每个元素添加到tmp集合中,然后进行
orig.swap(tmp);
这将交换集合的内部。
如果是我,我会把它封装在一个处理所有细节的新类中,这样您就可以根据需要更改实现。根据您的访问模式和排序顺序更改的次数,前面提到的向量、排序、低位解决方案可能更可取。
如果您可以使用无序集,那么为什么要首先将它们添加到集中?
我唯一能想到的情况是,当你添加列表时,你只想确保列表是唯一的。如果是这样的话,那么你可以使用一个临时设置来保护添加:
if (ts.insert (value).second) {
// insertion took place
realContainer.push_back (value);
}
另一种选择是,根据您修改集合中条目的频率,您可能可以测试条目是否在不同的位置(通过使用集合比较功能)以及位置将移动到哪里,然后删除旧条目并重新添加新条目。
正如其他人所指出的那样——让集合无序真的很难闻——我还猜测,根据标准,它可能会导致未定义的行为。
虽然这并不能完全满足您的需求,但boost::multi_index为您提供了类似的功能。由于模板的工作方式,您永远无法"更改"容器的排序谓词,它在编译时是固定不变的,除非您使用排序向量或类似的东西,否则您是保持不变的,您可以在任何给定时间按需排序。
但是,Multi_index为您提供了一种同时基于多个排序谓词对一组元素进行排序的方法。然后,您可以选择容器的视图,这些视图的行为类似于您当时关心的谓词排序的std::set。
这可能会导致条目丢失,当在set
中搜索元素时,会使用排序运算符,这意味着如果一个元素被放置在根的左边,而现在排序运算符说它在右边,则该元素将不再被找到。
这里有一个简单的测试:
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;
}
因此,基本上,如果您打算查找您曾经插入的元素,则不应更改用于插入和查找的谓词。
只是一个后续:
在运行此代码时,Visual Studio C调试库开始抛出异常,抱怨"<"运算符无效。
因此,改变排序似乎是一件坏事。谢谢大家!
1)有害-否。导致崩溃-否。最糟糕的情况确实是未排序的集合。
2) "刷新"和重新添加是一样的!
- 二叉排序树无法编译
- 仅使用绝对值对数组进行排序,并在C++中显示实际值
- C++选择排序算法中的逻辑错误
- 使用C++程序合并排序没有得到正确的输出
- 计算排序向量的向量中唯一值的计数
- C++取消引用指针.为什么会发生变化
- 为什么在读取文件大小时文件IO速度会发生变化
- 排序算法c++
- 使用2个键的cpp-stl::优先级队列排序不正确
- 将结构向量排序为子组
- 在c++中尝试对对象数组进行排序时,出现std:bad_alloc错误
- 如何对点云数据进行排序
- 对字符串进行排序时,在c++中处理sort()
- 是否有类似std::lower_bound的函数,而不需要排序/分区输入
- 下面是排序算法O(n)吗
- std::sort()函数无法对向量的一部分进行排序
- shell排序中的交换和比较
- clang格式:禁用排序包含
- C :重复的变化的递归功能,按不同字母数量排序
- STL排序集,其中的排序条件可能会发生变化