C++ 哪个STL容器最适合std::sort?(这有关系吗?)

C++ 哪个STL容器最适合std::sort?(这有关系吗?),c++,stl,sorting,C++,Stl,Sorting,标题不言而喻 容器的选择是否会以某种方式影响默认std::sort算法的速度?例如,如果我使用list,排序算法是只切换节点指针还是切换节点中的整个数据?这取决于元素类型 若你们只是存储指针(或POD),那个么向量将是最快的。如果您正在存储对象,则列表的排序将更快,因为它将交换节点而不是物理元素。我认为std::sort不适用于列表,因为它需要一个随机访问迭代器,而列表不提供该迭代器。请注意,list提供了一个sort方法,但它与std::sort完全分离 容器的选择很重要。STL的std::s

标题不言而喻


容器的选择是否会以某种方式影响默认std::sort算法的速度?例如,如果我使用list,排序算法是只切换节点指针还是切换节点中的整个数据?

这取决于元素类型


若你们只是存储指针(或POD),那个么向量将是最快的。如果您正在存储对象,则列表的排序将更快,因为它将交换节点而不是物理元素。

我认为
std::sort
不适用于列表,因为它需要一个随机访问迭代器,而
列表不提供该迭代器。请注意,
list
提供了一个
sort
方法,但它与
std::sort
完全分离


容器的选择很重要。STL的
std::sort
依赖于迭代器来抽象容器存储数据的方式。它只使用您提供的迭代器来移动元素。这些迭代器访问和分配元素的速度越快,
std::sort
的工作速度就越快。

排序算法对容器一无所知。它只知道随机访问迭代器。因此,您可以对STL容器中没有的内容进行排序。所以它的速度取决于你给它的迭代器,以及它去引用和复制它们指向的内容的速度


由于排序需要随机访问迭代器,所以std::sort在std::list上不起作用。对于这种情况,应该使用std::list的成员函数排序之一。这些成员函数将有效地交换链表指针,而不是复制元素。

std::list
对于
std::sort()
,绝对不是一个好的(有效的)选择,因为
std::sort()
需要随机访问迭代器<代码>标准::地图
和朋友也不好,因为元素的位置无法强制执行;也就是说,用户无法通过插入到特定位置或交换来强制地图中元素的位置。在标准容器中,我们可以使用
std::vector
std::deque

std::sort()
与其他标准算法类似,它只通过交换元素的值来起作用(
*t=*s
)。所以,即使列表神奇地支持O(1)访问,链接也不会被重新组织,而是它们的值会被交换


由于
std::sort()
不会更改容器的大小,因此无论使用
std::vector
还是
std::deque
,都不会影响运行时性能。基本数组的排序速度也应该很快,可能甚至比标准容器更快——但我不认为速度上的差异足以证明使用它们是合理的。

这当然很重要,因为不同的容器具有不同的内存访问模式等,这可能会起到一定的作用


但是,
std::sort
不适用于
std::list::迭代器
,因为它们不是随机访问迭代器。此外,尽管可以实现对
std::list
的专门化,以洗牌节点的指针,但它可能会产生奇怪和令人惊讶的语义后果-例如,如果向量中的排序范围内有一个迭代器,其值将在排序后改变,这在这种专门化中是不正确的。

选择确实会产生影响,但是预测哪个容器将是最有效的是非常困难的。最好的方法是使用应用程序最容易使用的容器(可能是std::vector),查看该容器的排序速度是否足够快,如果足够快,请使用它。如果没有,请对排序问题进行性能分析,并根据分析数据选择不同的容器


作为一名前讲师和前培训师,我有时觉得自己应该对一个普遍的想法负责,即链表具有神秘的性能提升特性。从一个知道的人那里可以看出:链表出现在如此多的教科书和教程中的唯一原因是,编写这些书籍和教程的人渴望拥有一个能够说明指针、动态内存管理、递归、,搜索和排序集于一身-这与效率无关。

std::sort需要随机访问迭代器,因此您唯一可以使用的选项是vector或deque。它将交换这些值,并且在猜测时,vector的执行速度可能会比deque稍快,因为它通常具有更简单的底层数据结构。不过,两者之间的差异可能非常微小

如果使用std::list,则有一个专门化(std::list::sort),它应该交换指针而不是值。然而,由于它不是随机访问,它将使用mergesort而不是quicksort,这可能意味着算法本身会稍微慢一点

无论如何,我认为答案通常是向量。如果每个元素都有大型类,所以复制开销在排序过程中占主导地位,列表可能会胜过它。或者,您也可以将指向它们的指针存储在向量中,并提供自定义谓词以对它们进行适当排序。

vector

始终使用vector作为默认值。它具有最低的空间开销和最快的访问速度(以及其他优势,如C兼容布局和随机访问迭代器)

现在,问问你自己——你还用你的容器做什么?你需要强有力的例外保证吗?列表、集合和映射可能是更好的选项(尽管它们都有自己的排序例程)。您是否需要定期向容器正面添加元素?考虑一下迪克。您的集装箱是否需要一直分拣?Set和map可能更适合

最后,明确指出什么是“最好的”对你来说,然后再选择cho
#include <iostream>
#include <vector>
#include <deque>
#include <array>
#include <list>
#include <iterator>
#include <cstdlib>
#include <algorithm>
#include "Timer.h"

constexpr int SIZE = 1005000;

using namespace std;

void test();

int main(){
    cout<<"array allocates "<<static_cast<double>(SIZE)/(1024*1024)<<" MB\n";
    test();


    return 0;
}


void test(){
    int values[SIZE];
    int size = 0;

    //init values to sort:
    do{
        values[size++] = rand() % 100000;
    }while(size < SIZE);

    //feed array with values:
    array<int, SIZE> container_1;
    for(int i = 0; i < SIZE; i++)
        container_1.at(i) = values[i];

    //feed vector with values
    vector<int> container_2(begin(values), end(values));
    list<int> container_3(begin(values), end(values)); 
    deque<int> container_4(begin(values), end(values)); 

    //meassure sorting time for containers
    {
       Timer t1("sort array");
       sort(container_1.begin(), container_1.end());
    }

    {
       Timer t2("sort vector");
       sort(container_2.begin(), container_2.end());
    }

    {
       Timer t3("sort list");
       container_3.sort();
    }

    {
       Timer t4("sort deque");
       sort(container_4.begin(), container_4.end());
    }

}
#include <chrono>
#include <string>
#include <iostream>

using namespace std;

class Timer{

public:
    Timer(string name = "unnamed") : mName(name){ mStart = chrono::system_clock::now();}
    ~Timer(){cout<<"action "<<mName<<" took: "<<
             chrono::duration_cast<chrono::milliseconds>(
                     chrono::system_clock::now() - mStart).count()<<"ms"<<endl;}
private:
    chrono::system_clock::time_point mStart;
    string mName;
};