r - 为什么 rcpp 中实现的快速排序运行缓慢?

标签 r quicksort rcpp

我在 Rcpp 中实现了快速排序算法,但对于大型数组,它的运行速度明显慢于 sort(array, method="quick")。为什么?

这是我的 Rcpp 代码

// partition using hoare's scheme

#include <Rcpp.h>
using namespace Rcpp;

int partition(NumericVector a,int start,int end)
{
    double pivot = a[end];
    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 1;
}

对于具有浮点值的数组,该算法也更糟糕。我想与hoare和lomuto分区方案进行比较,但我不知道这个实现是否有任何缺陷,哪个算法运行速度较慢。

最佳答案

代码效率低下的主要原因似乎是混合了要比较的两种分区方案。您声称使用 Hoare 分区方案,代码看起来非常像,但是 pivot 是根据 Lomuto 分区方案计算的。此外,如果 i >= j,则应返回 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. 

因此,虽然此方法比 R's sort 慢大约 7 倍,它的运行时间至少具有可比较的数量级。 (感谢@JosephWood 挖掘出链接)。和Wikipedia列出了这两种模式的更多改进。

顺便说一句,我还更改了包装函数以返回更改后的数组。这允许我使用 bench::mark 的默认行为,即比较返回的结果。我发现这很有用...

关于r - 为什么 rcpp 中实现的快速排序运行缓慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60134088/

相关文章:

R-使用覆盖和递归合并列表

python - 索引超出范围 - Python 中的快速排序

c++ - 双轴快速排序

r - 如何使用 Rcpp 将 C 库中的 C 结构暴露给 R

r - 通过在 R 中组合 mutate 和 case_when 创建新变量

r - 如何获得一列何时变得比另一列低以及何时变得更高?

r - 在 .filled.contour 中设置自动颜色级别? (克里格法)

c++ - 扫描快速排序拆分

r - 如何从 Rcpp 定义 R 函数?

r - 使用 Rcpp 运行的代码比使用 g++ 编译的更快