Takas neden std :: sort tarafından sadece kabımda 32'den fazla öğe varsa çağrılıyor?


13

Merhaba Basit bir sorum var:

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'den fazla öğe ile, sıralama çağırır swap. 32 veya daha az eleman olduğunda, elemanlar hala sıralanır ancak swapçağrılmaz.

  • X64'te MSVC ++ 2019 kullanıyorum.
  • Ne zaman swapçağrılır ve ne zaman çağrılmaz ve neden? Teşekkür ederim!
  • swapKopya atamada, yalnızca çağrıyı kopya atama işlecinden ayırmak için ayırmak için kullanmadım .

6
std::sorteleman sayısı 32 veya daha azsa ekleme sıralamasına başvurur, aksi takdirde hızlı sıralama kullanır.
Evg

@Evg Bu bir gereklilik mi yoksa bu bağlam için bir açıklama mı?
François Andrieux

2
@ FrançoisAndrieux, bu Microsoft standart kütüphanesinin uygulama detayıdır. Benim tahminim OP'nin gözlemlediği davranışın nedeni budur. Şu anda daha fazla ayrıntı elde etmek için kaynak kodunu arıyorum.
Evg

1
Kaynağın ilgili kısmı: while (_ISORT_MAX < (_Count = _Last - _First) && 0 < _Ideal)nerede _ISORT_MAX32 değeri verilir. <algorithm>VS 16.5.0 kullanım satırı 3447
ChrisMM

Herhangi bir dilde modern standart kütüphanelerde gerçek bir hızlı sıralama kullanılmaz. Tümü, yalnızca öğe sayısı yeterince büyük olduğunda hızlı bir sıralama olan değiştirilmiş karışık sürümleri kullanır. Örneğin, Java ve Python Timsort kullanırken .NET çerçevesi ve GCC'nin C ++ kütüphanesi Introsort kullanıyor . libstdc ++ ve libc ++ ayrıca kısa diziler için ekleme sıralaması kullanır. Bkz . Farklı STL uygulamalarında C ++ 11 std :: sort'de hangi algoritmalar kullanılır?
phuclv

Yanıtlar:


14

Microsoft std::sortuygulaması şöyle görünür :

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
}

Sıralanacak aralık 32 veya daha az öğeye sahipse, Sortekleme sıralaması kullanır. Ekleme sıralaması swap, uygulamasında kullanılmaz . Aksi takdirde, böl ve fethet hızlı sıralama kullanılır. Gelen uygulanması o çağırır iter_swap(iç Unguarded_partition), hangi dönüş çağrılarında swap:

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

Tüm bunlar uygulama detaylarıdır. Standart kitaplık uygulamasından diğerine farklılık gösterir.


1
libcxx , türe bağlı olarak 6 veya 30'dan daha küçük uzunluktaki diziler için ekleme sıralama kullanır. libstd ++ bunu 16 veya daha az elemandan oluşan diziler için yapar. Farklı STL uygulamalarında C ++ 11 std :: sort'de hangi algoritmalar kullanılır?
phuclv
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.