不使用sort方法按字母顺序排序数组

时间:2014-11-21 18:49:49

标签: ruby arrays sorting each alphabetical

我一直在研究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语句获取每个项目,如果数字大于下一个项目,则将其交换到数组中,继续执行此操作,直到最大数字位于开头。我原本以为这会颠倒我的数组,但它会按字母顺序排序。

有人能够告诉我这个算法按字母顺序排列的方式,以及它在什么时候看着起始字母是什么?

提前感谢您的帮助。我确信这是非常简单的事情,但经过多次搜索我无法理解它!

6 个答案:

答案 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])当然似乎意味着降序。

诀窍是firstsecond之间的关系没有排序;有时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

该算法比较所有可能的位置(无意义地包括沿对角线的值,其中firstsecond相等)。然而,需要注意的重要一点是,在对角线下方和左侧发生的掉期代表second位于first左侧的情况 - 后向情况。并且还要注意,这些案例发生在转发案件之后

基本上,这个算法的作用是对数组进行反向排序(如你所怀疑的那样),然后然后对它进行前向排序。可能不是真正的意图,但代码肯定很简单。

答案 2 :(得分:0)

你的理解有点偏。

你说:

  

然后if语句接受每个项目,如果数字大于下一个项目,则将其交换到数组中

但这不是if声明正在做的事情。

首先,封闭它的两个块只是设置迭代器firstsecond,每次从块的第一个元素到最后一个元素计数。 (这是效率低下的,但我们将在稍后讨论有效排序。或者只是看看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"]