ฉันเพิ่งเขียนคลาสเล็ก ๆที่ใช้อัลกอริทึม Bose-Nelson เพื่อสร้างเครือข่ายการเรียงลำดับในเวลารวบรวม
มันสามารถใช้เพื่อสร้างการเรียงลำดับที่รวดเร็วมากสำหรับ 10 หมายเลข
/**
* A Functor class to create a sort for fixed sized arrays/containers with a
* compile time generated Bose-Nelson sorting network.
* \tparam NumElements The number of elements in the array or container to sort.
* \tparam T The element type.
* \tparam Compare A comparator functor class that returns true if lhs < rhs.
*/
template <unsigned NumElements, class Compare = void> class StaticSort
{
template <class A, class C> struct Swap
{
template <class T> inline void s(T &v0, T &v1)
{
T t = Compare()(v0, v1) ? v0 : v1; // Min
v1 = Compare()(v0, v1) ? v1 : v0; // Max
v0 = t;
}
inline Swap(A &a, const int &i0, const int &i1) { s(a[i0], a[i1]); }
};
template <class A> struct Swap <A, void>
{
template <class T> inline void s(T &v0, T &v1)
{
// Explicitly code out the Min and Max to nudge the compiler
// to generate branchless code.
T t = v0 < v1 ? v0 : v1; // Min
v1 = v0 < v1 ? v1 : v0; // Max
v0 = t;
}
inline Swap(A &a, const int &i0, const int &i1) { s(a[i0], a[i1]); }
};
template <class A, class C, int I, int J, int X, int Y> struct PB
{
inline PB(A &a)
{
enum { L = X >> 1, M = (X & 1 ? Y : Y + 1) >> 1, IAddL = I + L, XSubL = X - L };
PB<A, C, I, J, L, M> p0(a);
PB<A, C, IAddL, J + M, XSubL, Y - M> p1(a);
PB<A, C, IAddL, J, XSubL, M> p2(a);
}
};
template <class A, class C, int I, int J> struct PB <A, C, I, J, 1, 1>
{
inline PB(A &a) { Swap<A, C> s(a, I - 1, J - 1); }
};
template <class A, class C, int I, int J> struct PB <A, C, I, J, 1, 2>
{
inline PB(A &a) { Swap<A, C> s0(a, I - 1, J); Swap<A, C> s1(a, I - 1, J - 1); }
};
template <class A, class C, int I, int J> struct PB <A, C, I, J, 2, 1>
{
inline PB(A &a) { Swap<A, C> s0(a, I - 1, J - 1); Swap<A, C> s1(a, I, J - 1); }
};
template <class A, class C, int I, int M, bool Stop = false> struct PS
{
inline PS(A &a)
{
enum { L = M >> 1, IAddL = I + L, MSubL = M - L};
PS<A, C, I, L, (L <= 1)> ps0(a);
PS<A, C, IAddL, MSubL, (MSubL <= 1)> ps1(a);
PB<A, C, I, IAddL, L, MSubL> pb(a);
}
};
template <class A, class C, int I, int M> struct PS <A, C, I, M, true>
{
inline PS(A &a) {}
};
public:
/**
* Sorts the array/container arr.
* \param arr The array/container to be sorted.
*/
template <class Container> inline void operator() (Container &arr) const
{
PS<Container, Compare, 1, NumElements, (NumElements <= 1)> ps(arr);
};
/**
* Sorts the array arr.
* \param arr The array to be sorted.
*/
template <class T> inline void operator() (T *arr) const
{
PS<T*, Compare, 1, NumElements, (NumElements <= 1)> ps(arr);
};
};
#include <iostream>
#include <vector>
int main(int argc, const char * argv[])
{
enum { NumValues = 10 };
// Arrays
{
int rands[NumValues];
for (int i = 0; i < NumValues; ++i) rands[i] = rand() % 100;
std::cout << "Before Sort: \t";
for (int i = 0; i < NumValues; ++i) std::cout << rands[i] << " ";
std::cout << "\n";
StaticSort<NumValues> staticSort;
staticSort(rands);
std::cout << "After Sort: \t";
for (int i = 0; i < NumValues; ++i) std::cout << rands[i] << " ";
std::cout << "\n";
}
std::cout << "\n";
// STL Vector
{
std::vector<int> rands(NumValues);
for (int i = 0; i < NumValues; ++i) rands[i] = rand() % 100;
std::cout << "Before Sort: \t";
for (int i = 0; i < NumValues; ++i) std::cout << rands[i] << " ";
std::cout << "\n";
StaticSort<NumValues> staticSort;
staticSort(rands);
std::cout << "After Sort: \t";
for (int i = 0; i < NumValues; ++i) std::cout << rands[i] << " ";
std::cout << "\n";
}
return 0;
}
โปรดทราบว่าแทนที่จะเป็นif (compare) swap
คำสั่งเราได้เขียนโค้ดโอเปอร์เรเตอร์ที่ประกอบไปด้วย min และ max อย่างชัดเจน นี่คือการช่วยเขยิบคอมไพเลอร์ให้ใช้รหัส branchless
มาตรฐาน
มาตรฐานต่อไปนี้ได้รับการรวบรวมด้วยเสียงดังกราว -O3 และวิ่งบนอากาศ macbook กลางปี 2012 ของฉัน
เรียงลำดับข้อมูลแบบสุ่ม
เปรียบเทียบกับรหัสของ DarioP นี่คือจำนวนมิลลิวินาทีที่ใช้ในการเรียงลำดับ 1 ล้าน 32- บิต int อาร์เรย์ขนาด 10:
Hardcoded Sort Net 10: 88.774 ms
Templated Bose-Nelson เรียงลำดับ 10: 27.815 ms
ใช้วิธีการ templated นี้เรายังสามารถสร้างเครือข่ายการเรียงลำดับตามเวลารวบรวมสำหรับองค์ประกอบอื่น ๆ
เวลา (เป็นมิลลิวินาที) เพื่อเรียง 1 ล้านอาร์เรย์ของขนาดต่างๆ
จำนวนมิลลิวินาทีสำหรับอาร์เรย์ขนาด 2, 4, 8 คือ 1.943, 8.655, 20.246 ตามลำดับ
มอบเครดิตให้กับGlenn Teitelbaumสำหรับการเรียงลำดับการแทรกที่ยังไม่ได้ควบคุม
นี่คือนาฬิกาเฉลี่ยต่อการเรียงลำดับสำหรับอาร์เรย์ขนาดเล็ก 6 องค์ประกอบ รหัสมาตรฐานและตัวอย่างสามารถพบได้ในคำถามนี้:
เรียงลำดับที่เร็วที่สุดของ 6 int อาร์เรย์คงที่
Direct call to qsort library function : 326.81
Naive implementation (insertion sort) : 132.98
Insertion Sort (Daniel Stutzbach) : 104.04
Insertion Sort Unrolled : 99.64
Insertion Sort Unrolled (Glenn Teitelbaum) : 81.55
Rank Order : 44.01
Rank Order with registers : 42.40
Sorting Networks (Daniel Stutzbach) : 88.06
Sorting Networks (Paul R) : 31.64
Sorting Networks 12 with Fast Swap : 29.68
Sorting Networks 12 reordered Swap : 28.61
Reordered Sorting Network w/ fast swap : 24.63
Templated Sorting Network (this class) : 25.37
มันทำงานได้เร็วเท่ากับตัวอย่างที่เร็วที่สุดในคำถามสำหรับ 6 องค์ประกอบ
ประสิทธิภาพสำหรับการเรียงลำดับข้อมูลที่เรียงลำดับ
บ่อยครั้งที่อินพุตแถวเรียงอาจถูกเรียงลำดับแล้วหรือเรียงเป็นส่วนใหญ่
ในกรณีเช่นนี้การเรียงลำดับการแทรกอาจเป็นทางเลือกที่ดีกว่า
คุณอาจต้องการเลือกอัลกอริทึมการเรียงลำดับที่เหมาะสมขึ้นอยู่กับข้อมูล
รหัสที่ใช้สำหรับมาตรฐานที่สามารถพบได้ที่นี่
if
ข้อความที่ซ้อนกันน่าจะดีที่สุด หลีกเลี่ยงการวนซ้ำ