我一直在研究Chris Pine的Ruby教程,目前正在研究一种不使用sort
对名称数组进行排序的方法。
我的代码如下。它完美无缺,但比我想象的更进一步!
puts "Please enter some names:"
name = gets.chomp
names = []
while name != ''
names.push name
name = gets.chomp
end
names.each_index do |first|
names.each_index do |second|
if names[first] < names[second]
names[first], names[second] = names[second], names[first]
end
end
end
puts "The names you have entered in alphabetical order are: " + names.join(', ')
这是我无法理解的分类。
我对它的理解是each_index
会查看数组中每个项目的位置。然后if
语句获取每个项目,如果数字大于下一个项目,则将其交换到数组中,继续执行此操作,直到最大数字位于开头。我原本以为这会颠倒我的数组,但它会按字母顺序排序。
有人能够告诉我这个算法按字母顺序排列的方式,以及它在什么时候看着起始字母是什么?
提前感谢您的帮助。我确信这是非常简单的事情,但经过多次搜索我无法理解它!
答案 0 :(得分:4)
我认为快速排序算法是比较容易理解的算法之一:
def qsort arr
return [] if arr.length == 0
pivot = arr.shift
less, more = arr.partition {|e| e < pivot }
qsort(less) + [pivot] + qsort(more)
end
puts qsort(["George","Adam","Michael","Susan","Abigail"])
您的想法是选择一个元素(通常称为pivot),然后将数组分区为小于pivot的元素以及大于或等于pivot的元素。然后递归地对每个组进行排序并与数据透视结合。
答案 1 :(得分:1)
我明白为什么你会感到困惑 - 我也是。看看算法在每次交换时的作用。我使用数字而不是名字来使订单更清晰,但它对字符串的工作方式相同:
names = [1, 2, 3, 4]
names.each_index do |first|
names.each_index do |second|
if names[first] < names[second]
names[first], names[second] = names[second], names[first]
puts "[#{names.join(', ')}]"
end
end
end
=>
[2, 1, 3, 4]
[3, 1, 2, 4]
[4, 1, 2, 3]
[1, 4, 2, 3]
[1, 2, 4, 3]
[1, 2, 3, 4]
在这种情况下,它从一个排序列表开始,然后进行一堆交换,然后按顺序放回去。如果你只看第一批掉期交易,你可能会误以为它会做一个降序排序。比较(交换if names[first] < names[second]
)当然似乎意味着降序。
诀窍是first
和second
之间的关系没有排序;有时first
位于左侧,有时位于右侧。这使整个算法难以推理。
我猜这个算法是一个奇怪的冒泡排序实现,我通常会看到这样实现:
names.each_index do |first|
(first + 1...names.length).each do |second|
if names[first] > names[second]
names[first], names[second] = names[second], names[first]
puts "[#{names.join(', ')}]"
end
end
end
如果在相同的已排序数字数组上运行此代码,则它不执行任何操作:数组已经排序,因此它不会交换任何内容。在此版本中,second
始终位于first
的右侧,并且仅当first
的值更大时才进行交换。在second
。所以在第一遍中(其中first
为0),最小的数字在位置0结束,在下一个通道中,下一个最小的数字在下一个位置结束,等等。
如果你在反向排序的数组上运行它,你可以看到它在做什么:
[3, 4, 2, 1]
[2, 4, 3, 1]
[1, 4, 3, 2]
[1, 3, 4, 2]
[1, 2, 4, 3]
[1, 2, 3, 4]
最后,这是一种可视化两种算法中发生的事情的方法。首先修改版本:
0 1 2 3
0 X X X
1 X X
2 X
3
垂直轴上的数字代表first
的值。水平方向上的数字代表second
的值。 X
表示算法比较并可能交换的位置。请注意,它只是对角线上方的部分。
以下是您在问题中提供的算法的相同可视化:
0 1 2 3
0 X X X X
1 X X X X
2 X X X X
3 X X X X
该算法比较所有可能的位置(无意义地包括沿对角线的值,其中first
和second
相等)。然而,需要注意的重要一点是,在对角线下方和左侧发生的掉期代表second
位于first
左侧的情况 - 后向情况。并且还要注意,这些案例发生在转发案件之后。
基本上,这个算法的作用是对数组进行反向排序(如你所怀疑的那样),然后然后对它进行前向排序。可能不是真正的意图,但代码肯定很简单。
答案 2 :(得分:0)
你的理解有点偏。
你说:
然后if语句接受每个项目,如果数字大于下一个项目,则将其交换到数组中
但这不是if
声明正在做的事情。
首先,封闭它的两个块只是设置迭代器first
和second
,每次从块的第一个元素到最后一个元素计数。 (这是效率低下的,但我们将在稍后讨论有效排序。或者只是看看Brian Adkins的回答。)
当您到达if语句时,它不会比较索引本身,而是比较这些索引的names
。
您可以通过在if
之前插入此行来查看正在发生的事情。虽然这会使你的程序非常冗长:
puts "Comparing names[#{first}] which is #{names[first]} to names[#{second}] which is #{names[second]}..."
答案 3 :(得分:0)
或者,您可以创建一个新数组并使用while循环按字母顺序附加名称。删除已在循环中追加的元素,直到旧数组中没有剩余元素。
sorted_names = []
while names.length!=0
sorted_names << names.min
names.delete(names.min)
end
puts sorted_names
答案 4 :(得分:0)
这是此案例的递归解决方案
<?php
RANDOM IMAGES
?>
XXX HTML CODE XXX
<?php
CONTINUOUS RANDOM IMAGE
?>
答案 5 :(得分:0)
这是我的代码,在不使用sort或min方法的情况下对数组中的项进行排序,同时考虑每个项的各种形式(例如字符串,整数,零):
def sort(objects)
index = 0
sorted_objects = []
while index < objects.length
sorted_item = objects.reduce do |min, item|
min.to_s > item.to_s ? item : min
end
sorted_objects << sorted_item
objects.delete_at(objects.find_index(sorted_item))
end
index += 1
sorted_objects
end
words_2 = %w{all i can say is that my life is pretty plain}
p sort(words_2)
=> ["all", "can", "i", "is", "is", "life", "my", "plain", "pretty", "say", "that"]
mixed_array_1 = ["2", 1, "5", 4, "3"]
p sort(mixed_array_1)
=> [1, "2", "3", 4, "5"]
mixed_array_2 = ["George","Adam","Michael","Susan","Abigail", "", nil, 4, "5", 100]
p sort(mixed_array_2)
=> ["", nil, 100, 4, "5", "Abigail", "Adam", "George", "Michael", "Susan"]