c++ - 使用迭代器对 std::list 进行排序
问题描述
是否可以像这样对迭代器定义的列表的一部分(列表的子集)进行排序std::sort
?
即,std::list
唯一可用的排序是通过一种方法(http://en.cppreference.com/w/cpp/container/list/sort),我希望能够使用它的迭代器对列表的一部分进行排序std::sort
。例如
std::sort(listItrStart, listItrEnd, [](T& a, T& b){ return a.something() < b.something()});
我很欣赏一旦对项目执行移动操作,迭代器就会失效,我认为这意味着如果在下一次“比较”之前不重新迭代到所需位置,列表就无法按迭代器排序?
在这种情况下,在不为此过程填充另一个容器(如果有的话)的情况下对列表子集进行排序的最佳实践是什么?
非常感谢。
解决方案
填充另一个容器是不可避免的。但是您不必移动或复制您自己的任何数据。您可以使用std::list::splice
提取和重新插入要处理的节点以排序。
using list_t = std::list<widget>;
void process(list_t& in, list_t::const_iterator begin, list_t::const_iterator end) {
list_t sorter;
sorter.splice(sorter.end(), in, begin, end);
sorter.sort();
in.splice(end, sorter);
}
该函数将您希望排序的节点转移到排序器列表中(第一个迭代器参数是插入节点之前的位置,在这种情况下是列表的末尾)。
排序器列表被排序(显然),然后排序的内容被传输回源列表,准确地进入它最初填充的原始子范围。
正如@TC 评论的那样,下一步是对其进行概括。它可以制作成一个很像这样的模板:
template<class List, class Compare = std::less<>>
void sort_subrange(List& in,
typename List::const_iterator begin,
typename List::const_iterator end,
Compare c = {}) {
List sorter(in.get_allocator());
sorter.splice(sorter.end(), in, begin, end);
[[maybe_unused]] ScopeGuard sg([&]() { in.splice(end, sorter); });
sorter.sort(std::move(c));
}
比较器在这里也被当作一个参数,并且sorter
是用输入分配器的副本构造的,以实现最大的通用性。拼接回是在我们选择的范围保护中完成的,以支持比较函数抛出的情况,所以我们的基础现在被覆盖了。
这是一个活生生的例子,为了说明目的,使用了一个幼稚且有点愚蠢的范围保护实现。
推荐阅读
- javascript - 间谍和赝品有什么区别?
- java - android.graphics.CornerPathEffect 是如何工作的?
- visual-studio-code - 关于跨多行拆分代码的 Visual Studio 代码问题
- mysql - mysql 使用带有 < 或 null 的索引
- python - Python SymPy 添加两个表达式
- android - 全文搜索 FTS4 错误 - 无法使用 MATCH 功能
- javascript - 有人可以解释缩短的代码如何等于更长的代码吗?
- python - 在使用 openpyxl 写入文件之前删除空白行
- sql - 如何使用循环插入数百万行数据(在预制的 H2 表中)?
- reactjs - 客户端不可用的环境变量