컨테이너에 32 개 이상의 요소가있는 경우에만 std :: sort가 스왑을 호출하는 이유는 무엇입니까?


13

안녕하세요, 간단한 질문이 있습니다.

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복사 할당에서 복사 할당 연산자와 정렬 호출을 구별하기 위해 복사 할당에 사용하지 않았습니다 .

6
std::sort요소 수가 32 이하인 경우 삽입 정렬을 사용하고 그렇지 않으면 빠른 정렬을 사용합니다.
평균

@Evg이 특정 상황에 대한 요구 사항입니까, 아니면 설명입니까?
François Andrieux

2
@ FrançoisAndrieux, 이것은 Microsoft 표준 라이브러리의 구현 세부 사항입니다. 내 생각에 이것이 OP에 의해 관찰 된 행동의 이유라고 생각합니다. 현재 소스 코드를 조사하여 자세한 내용을 얻고 있습니다.
평균

1
소스의 관련 부분은 다음과 같습니다. while (_ISORT_MAX < (_Count = _Last - _First) && 0 < _Ideal)여기서 _ISORT_MAX값은 32입니다. <algorithm>VS 16.5.0 을 사용하는 3434 행
ChrisMM

모든 언어의 최신 표준 라이브러리에는 실제 퀵 정렬이 사용되지 않습니다. 모든 요소가 충분히 큰 경우에만 빠른 정렬 인 수정 된 혼합 버전을 사용합니다. 예를 들어 Java와 Python은 Timsort 를 사용 하고 .NET 프레임 워크와 GCC의 C ++ 라이브러리는 Introsort를 사용 합니다 . libstdc ++ 및 libc ++도 짧은 시퀀스에 삽입 정렬을 사용합니다. 참조 알고리즘 (11) 표준 C ++에서 사용되는 어떤 :: 종류의 서로 다른 STL 구현에?
phuclv

답변:


14

Microsoft std::sort구현 은 다음 과 같습니다.

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삽입 정렬을 사용합니다. 삽입 정렬 사용하지 않는 swap그것의 구현 . 그렇지 않으면, 분할 및 정복 빠른 정렬이 사용됩니다. 에서 구현 이 호출 iter_swap(내부 Unguarded_partition), 차례 통화에서 swap:

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

이것들은 모두 구현 세부 사항입니다. 표준 라이브러리 구현마다 다릅니다.


1
libcxx 는 유형에 따라 길이가 6 또는 30보다 작은 시퀀스에 대해 삽입 정렬을 사용합니다. libstd ++ 는 16 요소 이하의 시퀀스에 대해 수행합니다. 다른 STL 구현에서 C ++ 11 std :: sort에 어떤 알고리즘이 사용됩니까?
phuclv
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.