Сортировка слиянием работает за время O ( n*log(n) ), как в среднем, так и в худшем случае.
Единственным недостатком для сортировки массива является необходимость наличия дополнительной памяти (buf)
равной по размеру исходному массиву (arr). Для сортировки списков дополнительная память не требуется.
template<class T>
ArrRef<T> mergeSort123 ( ArrRef<T> arr, ArrRef<T> buf )
{
const nat n = arr.size();
const nat small_size = sizeof(T) > 8 ? 32 : sizeof(T) > 4 ? 50 : 64;
if ( n < small_size ) return insertSort123 ( arr );
nat k = small_size / 2;
nat m = n, s = 0;
for(;;)
{
if ( m > k )
{
insertSort123 ( ArrRef<T> ( arr, s, k ) );
s += k;
m -= k;
}
else
{
insertSort123 ( ArrRef<T> ( arr, s, m ) );
break;
}
}
bool e = false;
do
{
T * a, * b;
if ( e )
{
b = arr();
a = buf();
}
else
{
a = arr();
b = buf();
}
nat i1 = 0;
for (;;)
{
T * p1 = a + i1;
nat i2 = i1 + k;
if ( i2 >= n )
{
T * a2 = a + n;
while ( p1 < a2 ) *b++ = *p1++;
break;
}
T * a2 = a + i2;
T * p2 = a2;
nat i3 = i2 + k;
if ( i3 > n ) i3 = n;
T * a3 = a + i3;
for (;;)
{
if ( *p1 <= *p2 )
{
*b++ = *p1++;
if ( p1 == a2 )
{
while ( p2 < a3 ) *b++ = *p2++;
break;
}
}
else
{
*b++ = *p2++;
if ( p2 == a3 )
{
while ( p1 < a2 ) *b++ = *p1++;
break;
}
}
}
i1 = i3;
}
e = !e;
k <<= 1;
}
while ( k < n );
if ( e )
{
for ( nat i = 0; i < n; ++i ) arr[i] = buf[i];
}
return arr;
}
Здесь переменные i1, i2, i3 обозначают соответственно: начало первого фрагмента из пары, начало второго фрагмента и начало следующей пары, если она есть. Аналогично устроен шаблон mergeSort321, который сортирует элементы массивов по убыванию. Описание шаблона классов ArrRef находится здесь.
|