簡體   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