Perché lo swap viene chiamato da std :: sort solo se il mio contenitore ha più di 32 elementi?


13

Ciao ho una semplice domanda:

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());

}

Con più di 32 elementi, l'ordinamento chiama swap. Con 32 elementi o meno, gli elementi vengono comunque ordinati ma swapnon vengono chiamati.

  • Sto usando MSVC ++ 2019 su x64.
  • Quando viene swapchiamato e quando non lo è e perché? Grazie!
  • Non ho usato swapnell'assegnazione della copia solo per distinguere la chiamata dall'ordinamento dall'operatore di assegnazione della copia.

6
std::sortricorre all'ordinamento per inserzione se il numero di elementi è 32 o inferiore e utilizza diversamente l'ordinamento rapido.
Evg

@Evg È un requisito o è una spiegazione per questo particolare contesto?
François Andrieux, il

2
@ FrançoisAndrieux, questo è un dettaglio di implementazione della libreria standard Microsoft. La mia ipotesi è che questa è la ragione del comportamento osservato dall'OP. Sto attualmente esaminando il codice sorgente per ottenere maggiori dettagli.
Evg

1
Parte rilevante della fonte è: while (_ISORT_MAX < (_Count = _Last - _First) && 0 < _Ideal)dove _ISORT_MAXviene dato il valore di 32. Riga 3447 <algorithm>dell'uso di VS 16.5.0
ChrisMM

Nessun vero quicksort è usato in nessuna libreria standard moderna in nessuna lingua. Tutti usano versioni miste modificate che è solo un quicksort quando il numero di elementi è abbastanza grande. Ad esempio Java e Python usano Timsort mentre .NET framework e la libreria C ++ di GCC usano Introsort . libstdc ++ e libc ++ usano anche l'ordinamento per inserzione per brevi sequenze. Vedi Quali algoritmi sono usati in C ++ 11 std :: sort in diverse implementazioni STL?
phuclv,

Risposte:


14

Microsoft std::sort implementazione presenta così:

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
}

Quando l'intervallo da ordinare ha 32 elementi o meno, Sortutilizza l'ordinamento per inserzione. L'ordinamento per inserzione non viene utilizzato swapnella sua implementazione . Altrimenti, viene utilizzato l'ordinamento rapido divide-and-conquer. Nella implementazione chiama iter_swap(interno Unguarded_partition), che in sua volta chiamate swap:

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

Tutti questi sono dettagli di implementazione. Variano da un'implementazione di libreria standard a un'altra.


1
libcxx usa l'ordinamento di inserzione per sequenze di lunghezza inferiore a 6 o 30 a seconda del tipo. libstd ++ lo fa per sequenze di 16 elementi o meno. Quali algoritmi sono utilizzati in C ++ 11 std :: sort in diverse implementazioni STL?
phuclv,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.