Основной причиной неэффективности вашего кода, похоже, является смешение двух схем разбиения, которые вы хотите сравнить. Вы утверждаете, что используете схему разбиения Hoare, и код очень похож на нее, но pivot
рассчитывается в соответствии со схемой разбиения Lomuto. Кроме того, вы должны вернуть j
, если i >= j
, а не, если i > j
. Исправив эти две вещи и заменив i++
на несколько более быстрый ++i
, я получаю:
// partition using hoare's scheme
#include <Rcpp.h>
using namespace Rcpp;
int partition(NumericVector a,int start,int end)
{
double pivot = a[(start + end) / 2];
int i = start - 1;
int j = end + 1;
//Rcout << a <<"\n";
while(1)
{
do {
++i;
} while (a[i] < pivot);
do {
--j;
} while (pivot < a[j]);
if(i >= j)
return j;
//special.Swap(a, i, j);
std::swap(a[i], a[j]);
}
}
void qsort(NumericVector a,int start,int end)
{
//Rcout << start <<"," << end <<"\n";
if(start < end)
{
int P_index = partition(a, start, end);
//Rcout << P_index << "\n";
qsort(a, start, P_index);
qsort(a, P_index + 1, end);
}
}
// [[Rcpp::export]]
NumericVector QuickSortH_WC(NumericVector arr)
{
int len = arr.size();
qsort(arr, 0, len-1);
//Rcout << arr <<"\n";
return arr;
}
/*** R
set.seed(42)
dat <- runif(1e6)
bench::mark(QuickSortH_WC(dat), sort(dat, method="quick"))
*/
Вывод
> bench::mark(QuickSortH_WC(dat), sort(dat, method="quick"))
# A tibble: 2 x 13
expression min median `itr/sec` mem_alloc `gc/sec` n_itr
<bch:expr> <bch:> <bch:t> <dbl> <bch:byt> <dbl> <int>
1 QuickSortH_WC(dat) 95.7ms 100.5ms 8.63 2.49KB 43.2 5
2 sort(dat, method = "quick") 15ms 16.5ms 53.1 11.44MB 23.6 27
# … with 6 more variables: n_gc <dbl>, total_time <bch:tm>, result <list>,
# memory <list>, time <list>, gc <list>
Warning message:
Some expressions had a GC in every iteration; so filtering is disabled.
Так что этот метод примерно в 7 раз медленнее, чем R sort
, он имеет по крайней мере сопоставимый порядок величины для времени выполнения. (Спасибо @JosephWood за то, что выкопали ссылку). И Википедия перечисляет еще больше улучшений по сравнению с этими двумя схемами.
Кстати, я также изменил функцию-обертку, чтобы она возвращала измененный массив. Это позволяет мне использовать поведение по умолчанию bench::mark
, которое заключается в сравнении возвращаемых результатов. Я считаю это полезным ...