我正在进行一些非常基本的算法练习,我对选择排序的这种实现感到困惑:
def selection_sort(xs)
len = xs.length
len.times do |i|
low = xs[i...len].min
tmp = xs[i]
xs[i] = low
xs[xs.rindex(low)] = tmp
end
xs
end
代码工作正常,但是,如果我使用xs[xs.index(low)] = tmp
而不是xs[xs.rindex(low)] = tmp
,则该函数在以下测试中无法正常工作:
selection_sort([3, 6, 2, 7, 4, 1, 4, 5, 6, 7, 8, 0])
selection_sort([0, 8, 7, 6, 5, 4, 1, 4, 7, 2, 6, 3])
在我看来,这应该无关紧要,因为索引是一个索引,无论它是来自右边还是左边。不会使用rindex
vs index
只更改流量(重复条目),但仍然输出有序列表?
我在俯瞰什么?
答案 0 :(得分:2)
正在发生的事情是,您在重新分配低值后测试索引,而不是在重新分配低值新位置的值之前测试索引。所以,让我们考虑一下:
xs = [4,3,2,1]
i = 2
low = [2, 1].min = 1
tmp = xs[i] = 2
现在,您指定xs[i] = low
,这意味着您的阵列现在看起来像[4,3,1,1]
。此时,xs.index(1)
将返回2
,因为您只是将低值放在该位置!使用rindex
会获得3
,因为它会找到用作低值的值,而不是您刚刚替换的值。
通过在第一次替换之前获取索引,您可以使index
调用对于没有重复值的列表起作用:
def selection_sort(xs)
len = xs.length
len.times do |i|
low = xs[i...len].min
tmp = xs[i]
tmpindex = xs.index(low)
xs[i] = low
xs[tmpindex] = tmp
end
xs
end
但是,由于您正在测试的列表确实具有重复值,因此您需要使用rindex来获取正确的偏移量,因为否则您可以获得超出i...len
范围界限的索引。
如果要在可包含多个值的列表上使用index
,则必须确保只在当前操作的切片中找到低值,然后通过切片将其偏移开始位置:
def selection_sort(xs)
xs.length.times do |i|
slice = xs[i..-1]
low, tmp = slice.min, xs[i]
xs[i], xs[i + slice.index(low)] = low, tmp
end
xs
end
此外,通过从slice
而非xs
获取索引,我们不必担心xs
中的更改,从而导致我们获得{{1}的错误索引}}