问题描述
我目前正在制作Robert Sedgewicks Algorithm's书。我正在尝试实现堆排序,但是遇到错误
'sink':未定义的方法>'表示nil:NilClass
发生此错误是由于将数组传递给sort
方法时,它在0索引处有11个元素。当它将索引n
(数组中元素的数量)与1交换时,会将nil
与一个字符串进行比较。意思是n
是11,但是没有11索引,因为数组索引从0开始。
这是本书中堆排序方法的Java实现:
public static void sort(Comparable[] a)
{
int N = a.length;
for (int k = N/2; k >= 1; k--)
sink(a,k,N);
while (N > 1)
{
exch(a,1,N--);
sink(a,N);
}
}
现在这是Ruby中的实现:
def sort(a)
n = a.length
k = n/2
while k >= 1
sink(a,n)
k -= 1
end
while n > 1
swap(a,n)
n -= 1
sink(a,n)
end
a
end
现在,在书中,数组忽略位置a[0]
并从a[1]
开始,但是我不清楚Java实施中的sort
方法是如何完成的。我也有点奇怪,该方法需要传递一个从索引1
开始的数组。因此,我的理解是Java实现中的sort
方法将设置数组。
在示例中,请注意数组中的第一个元素如何从索引1 a[1]
开始。这是通过sort
方法完成的吗?意味着要重新排列数组以从索引1开始?
在Ruby中sort
的Ruby实现正确吗?还是有错误?
完全实现堆排序。
class Heap
# Trickledown
def sink(a,n)
while 2 * k <= n
j = 2 * k # child
if !a[j + 1].nil? # check if there is a right child
j += 1 if j > 1 && less(a,j,j + 1) # if left child less than right child
end
break if !less(a,j) # If parent greater than child break
swap(a,j)
k = j
end
end
def sort(a)
n = a.length
k = n / 2
while k >= 1
sink(a,n)
k -= 1
end
while n > 1
swap(a,n)
end
a
end
def less(pq,i,j)
pq[i - 1] < pq[j - 1]
end
def swap(a,j)
temp = a[i - 1]
a[i - 1] = a[j - 1]
a[j - 1] = temp
end
end
input = ["S","O","R","T","E","X","A","M","P","L","E"]
heap = Heap.new
p heap.sort(input)
当我编辑less
和swap
方法以通过数组中的一个索引解决偏移时,这些方法在某些而非全部元素上可以正常工作。如果您检查最后一行是运行脚本的测试,但它将返回:
["A","S","X"]
但是正确的答案是
["A","X"]
解决方法
错误来自以下行:
if !a[j + 1].nil? # check if there is a right child
此行检查是否存在正确的节点。堆排序实现中的问题在于,每次迭代我们将n
减少1。
while n > 1
swap(a,1,n)
n -= 1
sink(a,n)
end
因此,我们没有跟踪索引n
以上的数组中存储的元素。尽管数组具有存储在数组中的值,但我们仅将a[0]
至a[n]
视为堆。
因此,我不应该检查a[j + 1]
是否为零,而是查看 j + 1
是否小于或等于n
。
def sink(a,k,n)
while 2 * k <= n
j = 2 * k # child
if j + 1 <= n # check if there is a right child
j += 1 if j > 1 && less(a,j,j + 1) # if left child less than right child
end
break if !less(a,j) # If parent greater than child break
swap(a,j)
k = j
end
end