合并在R中排序

Car*_*lli 2 sorting algorithm recursion mergesort r

我自学了Cormen et alli的"算法导论"一书.在他们的书中,他们使用伪代码,假定数组是通过指针(通过引用)传递的.这与R(其中对象按值传递)不同,因此我在尝试尽可能接近地转换伪代码时遇到一些困难,尤其是在涉及递归时.大多数时候,我必须以不同的方式实施.

例如,使用Merge Sort算法,它们定义合并函数(我认为我已正确翻译)和递归MergeSort函数(其中直接转换为R不起作用).

伪代码中的合并函数如下:其中:A是数组,p,q和r是数组的索引,使得p <q <r.该过程假设子阵列A [p:q]和A [q + 1:r]按排序顺序排列.它合并它们以形成一个替换当前子阵列A [p:r]的单个排序子阵列

Merge(A, p, q, r)
n1 = q - p + 1
n2 = r - q
let L[1...n1+1] and R[1...n2+1] be new arrays
for i = 1 to n1
    L[i] = A[p+i-1]
for j = 1 to n2
    R[j] = A[q+j]
L[n1+1] = infinite
R[n2+1] = infinite
i=1
j=1
for k = p to r
    if L[i] <= R[j]
        A[j] = L[i]
        i = i + 1
    else
        A[k] = R[j]
        j = j + 1
Run Code Online (Sandbox Code Playgroud)

我把它翻译为R:

Merge <- function(a, p, q, r){
  n1 <- q - p + 1
  n2 <- r - q
  L <- numeric(n1+1)
  R <- numeric(n2+1)
  for(i in 1:n1){
    L[i] <- a[p+i-1]
  }
  for(j in 1:n2){
    R[j] <- a[q+j]
  }
  L[n1+1] <- Inf
  R[n2+1] <- Inf
  i=1
  j=1
  for(k in p:r){
    if(L[i] <= R[j]){
      a[k] <- L[i]
      i <- i +1
    }else{
      a[k] <- R[j]
      j <- j+1
    }
  }
  a
}
Run Code Online (Sandbox Code Playgroud)

它似乎工作正常.

Merge(c(1,3,5, 2,4,6), 1, 3, 6)
[1] 1 2 3 4 5 6
Run Code Online (Sandbox Code Playgroud)

现在,MergeSort函数在伪代码中定义如下:

MergeSort(A, p, r)
if p < r
   q = (p+r)/2
   MergeSort(A, p, q)
   MergeSort(A, q+1, r)
   Merge(A, p, q, r)
Run Code Online (Sandbox Code Playgroud)

这假定A通过引用传递,并且每个递归调用都可以看到每个更改,这在R中是不正确的.

那么,鉴于Merge上面定义的函数,如何MergeSort在R中实现函数以获得正确的结果?(如果可能的话,最好的,但不是必需的,有点类似于伪代码)

MrF*_*ick 12

试图对一种语言编写的伪代码进行字面翻译,该语言允许以不支持它的语言进行传递,这是一个糟糕的主意.R不适用于函数内的数组切片.那不是一个合适的翻译.伪代码应该传达算法的精神,然后您将其转换为适当的语言.这里有一个可能的合并精神转化为R.

mmerge<-function(a,b) {
    r<-numeric(length(a)+length(b))
    ai<-1; bi<-1; j<-1;
    for(j in 1:length(r)) {
        if((ai<=length(a) && a[ai]<b[bi]) || bi>length(b)) {
            r[j] <- a[ai]
            ai <- ai+1
        } else {
            r[j] <- b[bi]
            bi <- bi+1          
        }
    }
    r
}
mmergesort<-function(A) {
    if(length(A)>1) {
        q <- ceiling(length(A)/2)
        a <- mmergesort(A[1:q])
        b <- mmergesort(A[(q+1):length(A)])
        mmerge(a,b)
    } else {
        A
    }
}
Run Code Online (Sandbox Code Playgroud)

你可以运行它

x<-c(18, 16, 8, 7, 6, 3, 11, 9, 15, 1)
mmergesort(x)
Run Code Online (Sandbox Code Playgroud)

在这个版本中,事物被引用替换:所有函数返回新值.另外,我们只是将向量子集化并将它们整体传递给函数,而不是传递幻灯片索引.

当然,由于在中间步骤中发生的所有内存重新分配,该版本的性能可能会受到影响.由于语言的设计方式,在基础R中你无能为力.如果您愿意,可以编写C/C++代码并通过外语接口调用它.

如果你想保持Merge原样(并忽略R-way来做事),那么你可以......

MergeSort<-function(A, p, r) {
    if(p < r) {
        q <- floor((p+r)/2)
        A <- MergeSort(A, p, q)
        A <- MergeSort(A, q+1, r)
        Merge(A, p, q, r)
    } else {
        A
    }
}
x <- c(18, 16, 8, 7, 6, 3, 11, 9, 15, 1)
MergeSort(x, 1, length(x))
Run Code Online (Sandbox Code Playgroud)

更新:

包括基准测试工具

m1<-function() {
    x<-sample(1000, 250);
    mmergesort(x)
}

m2<-function() {
    x<-sample(1000, 250);
    MergeSort(x, 1, length(x))
}

microbenchmark(m1(), m2())
Run Code Online (Sandbox Code Playgroud)