¿Por qué std :: sort llama a swap solo si mi contenedor tiene más de 32 elementos?

13

Hola tengo una pregunta simple:

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 más de 32 elementos, el tipo llama swap. Con 32 elementos o menos, los elementos todavía están ordenados pero swapno se llama.

  • Estoy usando MSVC ++ 2019 en x64.
  • ¿Cuándo se swapllama y cuándo no y por qué? ¡Gracias!
  • No utilicé swapen la asignación de copias solo para distinguir entre la llamada y la clasificación del operador de asignación de copias.
Maestro
fuente
66
std::sortrecurre a la ordenación por inserción si el número de elementos es 32 o menos, y de lo contrario utiliza la ordenación rápida.
Evg
@Evg ¿Es eso un requisito o es una explicación para este contexto particular?
François Andrieux
2
@ FrançoisAndrieux, este es un detalle de implementación de la biblioteca estándar de Microsoft. Supongo que esta es la razón del comportamiento observado por OP. Actualmente estoy buscando el código fuente para obtener más detalles.
Evg
1
La parte relevante de la fuente es: while (_ISORT_MAX < (_Count = _Last - _First) && 0 < _Ideal)donde _ISORT_MAXse le da el valor de 32. Línea 3447 de <algorithm>usar VS 16.5.0
ChrisMM
No se utiliza ninguna clasificación rápida real en ninguna biblioteca estándar moderna en ningún idioma. Todos usan versiones mixtas modificadas, que solo es una selección rápida cuando el número de elementos es lo suficientemente grande. Por ejemplo, Java y Python usan Timsort, mientras que .NET Framework y la biblioteca C ++ de GCC usan Introsort . libstdc ++ y libc ++ también usan el tipo de inserción para secuencias cortas. Consulte ¿Qué algoritmos se usan en C ++ 11 std :: sort en diferentes implementaciones de STL?
phuclv

Respuestas:

14

La std::sortimplementación de Microsoft se ve así:

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
}

Cuando el rango a ordenar tiene 32 elementos o menos, Sortusa el orden de inserción. La ordenación por inserción no se usa swapen su implementación . De lo contrario, se utiliza la clasificación rápida de divide y vencerás. En la implementación llama iter_swap(dentro Unguarded_partition), que a su vez llama swap:

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

Todos estos son detalles de implementación. Varían de una implementación de biblioteca estándar a otra.

Evg
fuente
1
libcxx usa el orden de inserción para secuencias de longitud menor que 6 o 30 dependiendo del tipo.libstd ++ hace eso para secuencias de 16 elementos o menos. ¿Qué algoritmos se usan en C ++ 11 std :: sort en diferentes implementaciones de STL?
phuclv