【问题标题】:Alphabetical sorting of an array without using the sort method不使用 sort 方法对数组进行字母排序
【发布时间】:2015-01-20 00:07:22
【问题描述】:

我一直在研究 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 语句获取每个项目,如果数字大于下一个,它将在数组中交换它,继续这样做直到最大的数字在开始。我原以为这只会颠倒我的数组,但是它确实按字母顺序排序。

有人能告诉我这个算法是如何按字母顺序工作的吗?它在什么时候查看起始字母是什么?

提前感谢您的帮助。我敢肯定这是非常简单的事情,但经过大量搜索后我无法弄清楚!

【问题讨论】:

    标签: ruby arrays sorting each alphabetical


    【解决方案1】:

    我认为快速排序算法是比较容易理解的算法之一:

    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"])
    

    这个想法是你选择一个元素(通常称为枢轴),然后将数组划分为小于枢轴的元素和大于或等于枢轴的元素。然后递归地对每个组进行排序并与枢轴组合。

    【讨论】:

      【解决方案2】:

      你的理解有点偏离。

      你说:

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

      但这不是if 语句正在做的事情。

      首先,包含它的两个块只是简单地设置迭代器firstsecond,每次通过块时,它们都从数组的第一个元素到最后一个元素计数。 (这是低效的,但我们将在稍后讨论有效排序。或者只是看看 Brian Adkins 的回答。)

      当您到达 if 语句时,它不是比较索引本身,而是比较这些索引处的 names

      您可以通过在if 之前插入这一行来查看发生了什么。虽然这会让你的程序变得非常冗长:

      puts "Comparing names[#{first}] which is #{names[first]} to names[#{second}] which is #{names[second]}..."
      

      【讨论】:

        【解决方案3】:

        我明白你为什么感到困惑——我也是。看看算法在每次交换时做了什么。我使用数字而不是名称来使顺序更清晰,但它对字符串的工作方式相同:

        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] &lt; 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 相等)。不过,需要注意的重要一点是,发生在对角线下方和左侧的交换表示secondfirst 左侧的情况——向后的情况。还要注意,这些情况发生在 前向情况之后。

        所以本质上,这个算法所做的就是对数组进行反向排序(正如您所怀疑的那样),然后然后对它进行正向排序。可能不是真正的预期,但代码确实很简单。

        【讨论】:

          【解决方案4】:

          或者,您可以创建一个新数组并使用 while 循环按字母顺序附加名称。删除循环中已经追加的元素,直到旧数组中没有元素为止。

          sorted_names = []
          
          while names.length!=0
              sorted_names << names.min
              names.delete(names.min)
          end
          
          puts sorted_names
          

          【讨论】:

            【解决方案5】:

            这是这种情况的递归解决方案

            def my_sort(list, new_array = nil)
            
              return new_array if list.size <= 0
              if new_array == nil
                new_array = []
              end
              min = list.min
              new_array << min
              list.delete(min)
            
              my_sort(list, new_array)
            
            end
            
            puts my_sort(["George","Adam","Michael","Susan","Abigail"])
            

            【讨论】:

              【解决方案6】:

              这是我在不使用 sort 或 min 方法的情况下对数组中的项目进行排序的代码,考虑到每个项目的各种形式(例如字符串、整数、nil):

              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"]
              

              【讨论】:

                猜你喜欢
                • 2023-04-04
                • 2021-07-26
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多