【问题标题】:Why is swap called by std::sort only if my container has more than 32 elements?为什么只有当我的容器有超过 32 个元素时,std::sort 才会调用 swap?
【发布时间】:2019-12-24 20:33:45
【问题描述】:

您好,我有一个简单的问题:

class A 
{
public:
    A(int);
    A(const A&);
    A& operator=(const A&);
    ~A();
private:
    int* ptr_;

    friend bool operator<(const A&, const A&);
    friend void swap(A&, A&);
};

A::A(int x) : 
    ptr_(new int(x))
{}

A::A(const A& rhs) :
    ptr_(rhs.ptr_ ? new int(*rhs.ptr_) : nullptr)
{}

A& A::operator = (const A & rhs)
{
    int* tmp = rhs.ptr_ ? new int(*rhs.ptr_) : nullptr;
    delete ptr_;
    ptr_ = tmp;

    return *this;
}

A::~A()
{
    delete ptr_;
}

bool operator<(const A& lhs, const A& rhs)
{
    cout << "operator<(const A&, const A&)" << endl;
    return *lhs.ptr_ < *rhs.ptr_;
}

void swap(A& lhs, A& rhs)
{
    cout << "swap(A&, A&)" << endl;
    using std::swap;
    swap(lhs.ptr_, rhs.ptr_);
}

int main()
{

    std::vector<A> v{ 33,32,31,30,29,28,27,26,25,24,23,22, 21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5, 4,3,2,1 };
    std::sort(v.begin(), v.end());

}

如果元素超过 32 个,则排序调用 swap。对于 32 个或更少的元素,元素仍会排序,但不会调用 swap

  • 我在 x64 上使用 MSVC++ 2019。
  • 什么时候调用swap,什么时候不调用,为什么?谢谢!
  • 我没有在复制分配中使用swap,只是为了区分来自复制分配运算符的排序调用。

【问题讨论】:

  • std::sort 如果元素个数为 32 或更少,则使用插入排序,否则使用快速排序。
  • @Evg 这是一个要求还是对这个特定上下文的解释?
  • @FrançoisAndrieux,这是微软标准库的实现细节。我的猜测是,这是 OP 观察到的行为的原因。我目前正在研究源代码以获取更多详细信息。
  • 来源的相关部分是:while (_ISORT_MAX &lt; (_Count = _Last - _First) &amp;&amp; 0 &lt; _Ideal) 其中_ISORT_MAX 的值是 32。&lt;algorithm&gt; 的第 3447 行使用 VS 16.5.0
  • 在任何语言的任何现代标准库中都没有使用真正的快速排序。全部使用修改后的混合版本,仅当元素数量足够大时才进行快速排序。例如,Java 和 Python 使用 Timsort,而 .NET 框架和 GCC 的 C++ 库使用 Introsort。 libstdc++ 和 libc++ 也对短序列使用插入排序。见What algorithms are used in C++11 std::sort in different STL implementations?

标签: c++ std swap


【解决方案1】:

微软std::sort 实现looks 像这样:

const int ISORT_MAX = 32;  // maximum size for insertion sort

template<class RanIt, class Diff, class Pr>
void Sort(RanIt First, RanIt Last, Diff Ideal, Pr Pred)
{
    Diff Count;
    for (; ISORT_MAX < (Count = Last - First) && 0 < Ideal; )
    {   // divide and conquer by quicksort
        pair<RanIt, RanIt> Mid = Unguarded_partition(First, Last, Pred);

        // ...
    }

    if (ISORT_MAX < Count)
    {   // heap sort if too many divisions
        Make_heap(First, Last, Pred);
        Sort_heap(First, Last, Pred);
    }
    else if (1 < Count)
        Insertion_sort(First, Last, Pred);  // small
}

当要排序的范围有 32 个或更少的元素时,Sort 使用插入排序。插入排序在其implementation 中不使用swap。否则,使用分而治之的快速排序。在implementation 中调用iter_swap(在Unguarded_partition 中),which 依次调用swap

template<class FwdIt1, class FwdIt2>
void iter_swap(FwdIt1 Left, FwdIt2 Right)
{   // swap *Left and *Right
    swap(*Left, *Right);
}

所有这些都是实现细节。它们因一种标准库实现而异。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-12-22
  • 2021-10-01
  • 1970-01-01
  • 2013-07-28
  • 2022-01-17
  • 2020-11-03
相关资源
最近更新 更多