В случае Visual Studio std :: sort() представляет собой комбинацию быстрой сортировки, сортировки кучи (только для предотвращения сложной ситуации с наихудшим случаем O (n^2)) и сортировки вставки, а std :: stable_sort(), представляет собой комбинацию сортировки и сортировки слиянием. Оба являются достаточно быстрыми, но можно писать более быстрый код. Пример кода в вопросе - копирование данных перед каждым слиянием, которое потребляет время. Этого можно избежать, выполняя одноразовое распределение рабочего буфера и переключая направление слияния на основе уровня рекурсии, используя пару взаиморекурсивных функций (показано ниже) или логический параметр для управления направлением слияния (не используется в примере ниже).
Пример кода C++ для сортировки по методу сверху вниз, который достаточно оптимизирован (сортировка слияния снизу вверх будет немного быстрее, поскольку она пропускает рекурсию, используемую для генерации индексов, вместо этого использует итерацию).
// prototypes
void TopDownSplitMergeAtoA(int a[], int b[], size_t ll, size_t ee);
void TopDownSplitMergeAtoB(int a[], int b[], size_t ll, size_t ee);
void TopDownMerge(int a[], int b[], size_t ll, size_t rr, size_t ee);
void MergeSort(int a[], size_t n) // entry function
{
if(n < 2) // if size < 2 return
return;
int *b = new int[n];
TopDownSplitMergeAtoA(a, b, 0, n);
delete[] b;
}
void TopDownSplitMergeAtoA(int a[], int b[], size_t ll, size_t ee)
{
if((ee - ll) == 1) // if size == 1 return
return;
size_t rr = (ll + ee)>>1; // midpoint, start of right half
TopDownSplitMergeAtoB(a, b, ll, rr);
TopDownSplitMergeAtoB(a, b, rr, ee);
TopDownMerge(b, a, ll, rr, ee); // merge b to a
}
void TopDownSplitMergeAtoB(int a[], int b[], size_t ll, size_t ee)
{
if((ee - ll) == 1){ // if size == 1 copy a to b
b[ll] = a[ll];
return;
}
size_t rr = (ll + ee)>>1; // midpoint, start of right half
TopDownSplitMergeAtoA(a, b, ll, rr);
TopDownSplitMergeAtoA(a, b, rr, ee);
TopDownMerge(a, b, ll, rr, ee); // merge a to b
}
void TopDownMerge(int a[], int b[], size_t ll, size_t rr, size_t ee)
{
size_t o = ll; // b[] index
size_t l = ll; // a[] left index
size_t r = rr; // a[] right index
while(1){ // merge data
if(a[l] <= a[r]){ // if a[l] <= a[r]
b[o++] = a[l++]; // copy a[l]
if(l < rr) // if not end of left run
continue; // continue (back to while)
while(r < ee) // else copy rest of right run
b[o++] = a[r++];
break; // and return
} else { // else a[l] > a[r]
b[o++] = a[r++]; // copy a[r]
if(r < ee) // if not end of right run
continue; // continue (back to while)
while(l < rr) // else copy rest of left run
b[o++] = a[l++];
break; // and return
}
}
}
Почему вы думаете, что это не O (N log N)? –
Похоже, вы делаете копию данных в каждом вызове 'merge'. Довольно уверен, что 'std :: sort' этого не делает. Это может быть ваша разница. – NathanOliver
Не потому, что алгоритм требует двойного времени, что он работает в другой временной сложности. –