繁体   English   中英

使用迭代器对std :: list进行排序

[英]Sorting a std::list using iterators

是否有可能对由std::sort这样的迭代器定义的列表(列表的子集)进行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以获得最大的通用性。 拼接在我们选择的范围内进行,以支持比较函数抛出的情况,因此我们的基础现在已被覆盖。

这是一个现实的例子 ,为了展示目的,有一个天真的,有点愚蠢的范围保护实现。

是否有可能对由std :: sort这样的迭代器定义的列表(列表的子集)进行排序?

我假设你的意思是std :: list :: sort。 Visual Studio 2015的实现可以做到这一点,而无需填充另一个容器。 它是一种自上而下的合并排序,效率低于之前的自下而上合并排序,但它避免了分配先前版本所做的内存,因为先前版本分配了一小部分列表。 Psuedo代码看起来像这样:

    right = std::next(right, 1);   // right = end of sub-list
    size = std::distance(left, right);
    left = MyListSort(list, left, right, size);
    right = std::next(left, size-1);  // right = last element of sub-list
    // ...
    MyListSort(list, left, right, size)
    {
        if(size < 2)
            return left;
        mid = std::next(left, size/2);
        MyListSort(list, left, mid, size/2);
        MyListSort(list, mid, right, size-size/2);
        firstloop = true;
        newleft = left;
        while(true){
            if(*left <= *mid){
                if(++left == mid)
                    return newleft;
            } else {
                if(firstloop)
                    newleft = mid;
                list.splice(left, list, mid);
                if(++mid == right)
                    return newleft;
            }
            firstloop = false;
        }
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM