我正在自学这本书"Introduction to Algorithms" by Cormen et alli.在他们的书中,他们使用伪代码,假设数组是通过指针(通过引用)传递的。这与R(其中对象按值传递)不同,因此我在尝试尽可能接近地转换伪代码时遇到一些困难,尤其是在涉及递归时。大多数时候,我必须以不同的方式实施。
例如,使用合并排序算法,它们定义合并函数(我认为我已正确翻译)和递归MergeSort函数(其中直接转换为R不起作用)。
伪代码中的合并函数如下:其中:A是数组,p,q和r是数组的索引,使得p <1。 q&lt;河该过程假设子阵列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
我将其翻译为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
}
似乎工作正常。
Merge(c(1,3,5, 2,4,6), 1, 3, 6)
[1] 1 2 3 4 5 6
现在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)
这假定A通过引用传递,并且每个递归调用都可以看到每个更改,这在R中是不正确的。
那么,给定上面定义的Merge
函数,如何在R中实现MergeSort
函数以获得正确的结果? (如果可能,并且更可取,但不是必需的,有点类似于伪代码)
答案 0 :(得分:11)
尝试对一种语言编写的伪代码进行字面翻译,该语言允许以不支持它的语言进行传递,这是一个可怕的想法。 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
}
}
您可以使用
运行它x<-c(18, 16, 8, 7, 6, 3, 11, 9, 15, 1)
mmergesort(x)
在此版本中,通过引用替换了所有函数:所有函数都返回新值。另外,我们只是将向量子集化并将它们整体传递给函数,而不是传递幻灯片索引。
当然,由于在中间步骤中发生的所有内存重新分配,此版本的性能可能会受到影响。由于语言的设计方式,在基础R中你无能为力。如果您愿意,可以编写C / C ++代码并通过foreign language interfaces调用它。
如果你想保持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))
更新:
包括基准测试工具
m1<-function() {
x<-sample(1000, 250);
mmergesort(x)
}
m2<-function() {
x<-sample(1000, 250);
MergeSort(x, 1, length(x))
}
microbenchmark(m1(), m2())
答案 1 :(得分:0)
此解决方案只获取一次长度且逻辑更简单。合并是在归并排序内部实现的:
mergesort = function(x){
l = length(x)
if(l==1)
{
return(x)
}
else
{
a = mergesort(x[1:((l - l %% 2)/2)])
b = mergesort(x[((l + 2 - l %% 2)/2):l])
a = c(a, Inf)
b = c(b, Inf)
for(el in 1:l){
if(a[1]>=b[1]){
x[el] = b[1]
b = b[-1]
}
else{
x[el] = a[1]
a = a[-1]
}
}
return(x)
}
}