用ruby实现shell排序
我尝试用ruby实现shell排序用ruby实现shell排序,ruby,sorting,Ruby,Sorting,我尝试用ruby实现shell排序 def shell_sort(list) d = list.length return -1 if d == 0 (0...list.length).each do |i| d = d / 2 puts "d:#{d}" (0...(list.length-d)).each do |j| if list[j] >= list[j+d] list[j], list[j+d] = list[j
def shell_sort(list)
d = list.length
return -1 if d == 0
(0...list.length).each do |i|
d = d / 2
puts "d:#{d}"
(0...(list.length-d)).each do |j|
if list[j] >= list[j+d]
list[j], list[j+d] = list[j+d], list[j]
end
end
puts list.inspect
break if d == 1
end
list
end
puts shell_sort([10,9,8,7,6,5,4,3,2,1]).inspect
但结果是不正确的
=>[2, 1, 3, 4, 5, 7, 6, 8, 9, 10]
我不知道哪里出了问题,希望有人能帮我。提前谢谢 我认为你的算法需要稍微调整一下 它失败的原因很简单,因为在最后一次运行中,当d==1时,最小的元素1与第一个元素的距离不够近,无法一次性交换 使其工作的最简单方法是在元素切换位置时重新启动内部循环。所以,稍微粗略一点的解决方案应该是
(0...(list.length-d)).each do |j|
if list[j] >= list[j+d]
list[j], list[j+d] = list[j+d], list[j]
d *= 2
break
end
end
这个解决方案当然远不是最优的,但应该用尽可能少的代码实现所需的结果。您应该在阵列上执行最后一次运行。为了简化您的代码,我将exchange部件提取为独立功能,以便您现在可以看到应该在何处执行此操作:
def exchange e, list
(0...(list.length-e)).each do |j|
if list[j] >= list[j+e]
list[j], list[j+e] = list[j+e], list[j]
end
end
end
def shell_sort(list)
d = list.length
return -1 if d == 0
(0...list.length).each do |i|
d = d / 2
puts "d:#{d}"
exchange(d, list)
puts list.inspect
if d == 1
exchange(d, list)
break
end
end
list
end
arr = [10,9,8,7,6,5,4,3,2,1]
p shell_sort(arr)
结果:
#> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
我在这里引用了Shell Sort:,由此我了解到您的算法是错误的。间隔序列的迭代是可以的,我的意思是你只迭代到d/2==1 但对于间隙,比如说2,您只需从0迭代到list.length-2,如果list[j]大于list[j+2],则交换每个j和j+2元素。这甚至不是一个正确的插入排序,Shell排序要求对间隙进行插入排序。此外,Shell排序要求在执行x间隙排序后,从任意位置开始的每个xth元素都将被排序。请参见链接上的示例运行,您可以验证自己 在2间隙排序过程中可能出错的情况:
list = 5,4,3,2,1
j = 0 passed :
list = 3,4,5,2,1
j = 1 passed :
list = 3,2,5,4,1
j = 2 passed
list = 3,2,1,4,5
完成后,您可以看到从0开始的第二个元素不是按排序顺序排列的。我建议您先学习插入排序,然后了解它在Shell排序中的使用位置和方式,如果您想自己做的话,请再试一次
不管怎样,我已经写了一篇文章,如果你想把你的方法作为基础的话,留着以后用,还有很多评论。希望你能从中了解到这个想法。还试图使输出阐明算法的工作原理
def shell_sort(list)
d = list.length
return -1 if d == 0
# You select and iterate over your gap sequence here.
until d/2 == 0 do
d = d / 2
# Now you pick up an index i, and make sure every dth element,
# starting from i is sorted.
# i = 0
# while i < list.length do
0.step(list.length) do |i|
# Okay we picked up index i. Now it's just plain insertion sort.
# Only difference is that we take elements with constant gap,
# rather than taking them up serially.
# igap = i + d
# while igap < list.length do
(i+d).step(list.length-1, d) do |igap|
# Just like insertion sort, we take up the last most value.
# So that we can shift values greater than list[igap] to its side,
# and assign it to a proper position we find for it later.
temp = list[igap]
j = igap
while j >= i do
break if list[j] >= list[j - d]
list[j] = list[j-d]
j -= d
end
# Okay this is where it belongs.
list[j] = temp
#igap += d
end
# i += 1
end
puts "#{d} sort done, the list now : "
puts list.inspect
end
list
end
list = [10,9,8,7,6,5,4,3,2,1]
puts "List before sort : "
puts list.inspect
shell_sort(list)
puts "Sorted list : "
puts list.inspect
为什么不使用list.sort?@floum大概是为了练习。@floum@Jesse-Mu是对的,我知道如何使用sort方法,只是想练习一下算法。