Ruby Heapsort:`sink':nil:NilClass的未定义方法'>'

问题描述

我目前正在制作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方法将设置数组。

enter image description here

在示例中,请注意数组中的第一个元素如何从索引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)

当我编辑lessswap方法以通过数组中的一个索引解决偏移时,这些方法在某些而非全部元素上可以正常工作。如果您检查最后一行是运行脚本的测试,但它将返回:

["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]视为堆。 enter image description here

因此,我不应该检查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

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...