【问题标题】:Efficiency of std::sort() algorithm in sorting std::vector of std::liststd::sort() 算法在对 std::list 的 std::vector 进行排序时的效率
【发布时间】:2021-10-28 19:12:07
【问题描述】:

下面的例子取自 Jossuttis(2012),做了一些小的改动。

本质上,它是对整数列表的向量进行排序。

我的问题如下:

  1. std::sort() 算法是否对指针(指向列表)进行排序?
  2. 如果答案是否定的,那么仍然使用 std::sort() 对指向容器的(智能)指针向量进行排序的最佳方法是什么?
#include <vector>
#include <list>
#include <algorithm>
#include <iterator>
#include <functional>
using namespace std;

template<typename T>

inline void INSERT_ELEMENT(T& coll, int first, int last){
    for(int i=first; i<=last; ++i)
        coll.insert(coll.end(), i);
}

template<typename T>

inline void PRINT_ELEMENTS(const T& coll, const std::string& optcstr=""){
    std::cout << optcstr;
    for(auto elem:coll)
        std::cout << elem << " ";
    std::cout << std::endl;
}

int main(){

    list<int> c1, c2, c3, c4;
    INSERT_ELEMENT(c1, 1, 5);
    c2 = c3 = c4 = c1;

    c1.push_back(7);
    c3.push_back(2);
    c3.push_back(0);
    c4.push_back(2);

    vector<list<int>> cc{ c1, c2, c3, c4, c3, c1, c4, c2};

    for(auto elem: cc){
        PRINT_ELEMENTS(elem);
    }
    cout << endl;

    sort(
        cc.begin(), 
        cc.end(), 
        [](const list<int>& first, const list<int>& second){
            return lexicographical_compare(
                first.cbegin(), 
                first.cend(),
                second.cbegin(),
                second.cend()
            );
        }
    );
    for(auto elem: cc){
        PRINT_ELEMENTS(elem);
    }
}

【问题讨论】:

  • 我在这里看不到任何指针的用法。是什么让您相信其中涉及到指针? “最好的方法”是什么意思?
  • 运行代码应该回答你的问题,不是吗?
  • 你的排序标准是什么?
  • 当您使用比较排序对对象数组/向量进行排序时,您可以在对象乱序时交换对象或交换指向对象的指针。如果对象很大,则需要后一种方法。在我的示例中,列表很小,但如果它们很大,那么最小化内存中大对象移动的最佳方法是什么?我的意思是,最好的方式是使用可以在销毁时释放它们指向的所有内存的指针。

标签: c++ sorting stl smart-pointers


【解决方案1】:

std::sort() 算法是否对指针(指向列表)进行排序?

不,在 c++11 或 c++03 中都没有。不同之处在于c++11以来,移动语义用于排序。

我认为您实际上被问到的是关于 move 语义的问题。对于std::list,它们是可移动的,在std::sort的实现中,元素交换是基于c++11中的移动。所以从 c++11 开始,std::vector&lt;std::list&lt;T&gt;&gt; 的那种很便宜。如果你有 pre c++11,那么我们可以考虑使用指针来使交换(基于副本)便宜:std::vector&lt;std::list&lt;T&gt;*&gt; 使排序更快,建议升级旧编译器以获得性能提升。

您可以通过更改代码来打印元素地址来验证它,排序后它们没有更改,然后我们确认列表已移动但未复制,您的原始代码在for循环范围内有不必要的复制,我已修复它:

#include <algorithm>
#include <functional>
#include <iostream>
#include <iterator>
#include <list>
#include <vector>
using namespace std;

template <typename T>

inline void INSERT_ELEMENT(T& coll, int first, int last) {
  for (int i = first; i <= last; ++i) coll.insert(coll.end(), i);
}

template <typename T>

inline void PRINT_ELEMENTS(const T& coll, const std::string& optcstr = "") {
  std::cout << optcstr;
  for (auto& elem : coll) std::cout << &elem << " ";
  std::cout << std::endl;
}

int main() {
  list<int> c1, c2, c3, c4;
  INSERT_ELEMENT(c1, 1, 5);
  c2 = c3 = c4 = c1;

  c1.push_back(7);
  c3.push_back(2);
  c3.push_back(0);
  c4.push_back(2);

  vector<list<int>> cc{c1, c2, c3, c4, c3, c1, c4, c2};

  for (auto& elem : cc) {
    PRINT_ELEMENTS(elem);
  }
  cout << endl;

  sort(cc.begin(), cc.end(),
       [](const list<int>& first, const list<int>& second) {
         return lexicographical_compare(first.cbegin(), first.cend(),
                                        second.cbegin(), second.cend());
       });
  for (auto& elem : cc) {
    PRINT_ELEMENTS(elem);
  }
}

Online demo

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2012-01-21
  • 2011-01-08
  • 2010-09-19
  • 2013-06-27
  • 1970-01-01
  • 2011-06-04
  • 1970-01-01
  • 2021-01-21
相关资源
最近更新 更多