Son zamanlarda derleme zamanında bir sıralama ağı oluşturmak için Bose-Nelson algoritmasını kullanan küçük bir sınıf yazdım .
10 numara için çok hızlı bir sıralama oluşturmak için kullanılabilir.
/**
* 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;
}
Bir if (compare) swap
ifade yerine, üçlü operatörleri min ve max olarak açıkça kodladığımızı unutmayın. Bu, derleyiciyi dalsız kod kullanarak sürüklemeye yardımcı olmak içindir.
Deneyler
Aşağıdaki kriterler clang -O3 ile derlenmiş ve 2012 ortası macbook air'imde yayınlanmıştır.
Rasgele verileri sıralama
DarioP koduyla karşılaştırıldığında, 10 büyüklüğünde 1 milyon 32 bit int dizisini sıralamak için geçen milisaniye sayısı:
Sabit Kodlu Sıralama Net 10: 88.774 ms
Templated Bose-Nelson sıralama 10: 27.815 ms
Bu şablon yaklaşımı kullanarak, diğer sayıda öğe için derleme zamanında sıralama ağları da oluşturabiliriz.
Çeşitli boyutlardaki 1 milyon diziyi sıralama zamanı (milisaniye cinsinden).
2, 4, 8 boyutlu diziler için milisaniye sayısı sırasıyla 1.943, 8.655, 20.246'dır.
Açılmamış yerleştirme sıralaması için Glenn Teitelbaum'a kredi .
İşte 6 elementten oluşan küçük diziler için tür başına ortalama saatler. Karşılaştırma kodu ve örnekleri şu soruda bulunabilir:
En hızlı sabit uzunluk 6 int dizisi
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 eleman için sorudaki en hızlı örnek kadar hızlı performans gösterir.
Sıralı verileri sıralama performansı
Genellikle, girdi dizileri zaten sıralanmış veya çoğunlukla sıralanmış olabilir.
Bu gibi durumlarda, yerleştirme sıralaması daha iyi bir seçim olabilir.
Verilere bağlı olarak uygun bir sıralama algoritması seçmek isteyebilirsiniz.
Karşılaştırma ölçütleri için kullanılan kodu burada bulabilirsiniz .
if
ifade en iyi şekilde çalışmalıdır. Döngülerden kaçının.