เหตุใด swap ถูกเรียกโดย std :: sort ก็ต่อเมื่อคอนเทนเนอร์ของฉันมีองค์ประกอบมากกว่า 32 ตัว?


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ไม่ได้เรียกว่า

  • ฉันใช้ MSVC ++ 2019 ใน x64
  • เมื่อไหร่ที่ถูกswapเรียกและเมื่อไรที่ไม่ได้และทำไม ขอบคุณ!
  • ฉันไม่ได้ใช้swapในการคัดลอกการมอบหมายเพื่อแยกความแตกต่างระหว่างการโทรจากการเรียงลำดับจากผู้ดำเนินการคัดลอกการมอบหมาย

6
std::sortการเรียงลำดับการแทรกหากจำนวนองค์ประกอบเป็น 32 หรือน้อยกว่าและใช้การเรียงลำดับอย่างรวดเร็ว
Evg

@Evg นั่นเป็นข้อกำหนดหรือว่าเป็นคำอธิบายสำหรับบริบทเฉพาะนี้หรือไม่?
François Andrieux

2
@ FrançoisAndrieuxนี่คือรายละเอียดการใช้งานของไลบรารีมาตรฐานของ Microsoft ฉันเดาว่านี่คือเหตุผลของพฤติกรรมที่สังเกตโดย OP ฉันกำลังดูซอร์สโค้ดเพื่อรับรายละเอียดเพิ่มเติม
Evg

1
ส่วนที่เกี่ยวข้องของแหล่งที่มาคือ: while (_ISORT_MAX < (_Count = _Last - _First) && 0 < _Ideal)ที่_ISORT_MAXได้รับค่า 32 บรรทัด 3447 ของการ<algorithm>ใช้ VS 16.5.0
ChrisMM

ไม่มีการใช้ quicksort จริงในไลบรารีมาตรฐานที่ทันสมัยในภาษาใด ๆ ใช้ผสมเวอร์ชันดัดแปลงทั้งหมดซึ่งเป็นเพียงอย่างรวดเร็วเมื่อจำนวนองค์ประกอบมีขนาดใหญ่พอ ตัวอย่างเช่น Java และ Python ใช้ Timsortขณะที่กรอบ NET และ GCC ของ C ++ ใช้งานห้องสมุดIntrosort libstdc ++ และ libc ++ ใช้การเรียงลำดับการแทรกสำหรับลำดับสั้น ๆ ดูอัลกอริทึมใดที่ใช้ใน C ++ 11 std :: sort ในการใช้งาน STL ที่แตกต่างกัน?
phuclv

คำตอบ:


14

std::sortการใช้งานของ Microsoft มีลักษณะเช่นนี้:

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 องค์ประกอบหรือน้อยกว่า อัลกอริทึมใดที่ใช้ใน C ++ 11 std :: sort ในการใช้งาน STL ที่แตกต่างกัน?
phuclv
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.