【问题标题】:how to make a sorting method in smalltalk如何在smalltalk中制作排序方法
【发布时间】:2015-04-30 04:11:22
【问题描述】:

我正在尝试在 smalltalk 中创建一种新的排序方法。任何人都知道如何将这种排序 java 代码更改为吱吱声?

public static void SelectionSort ( int [ ] num )
{
     int i, j, first, temp;  
     for ( i = num.length - 1; i > 0; i - - )  
     {
          first = 0;   //initialize to subscript of first element
          for(j = 1; j <= i; j ++)   //locate smallest element between positions 1 and i.
          {
               if( num[j] < num[first] )         
                 first = j;
          }
          temp = num[first];   //swap smallest found with element in position i.
          num[first] = num[ i ];
          num[i] = temp; 
      }           
}

【问题讨论】:

    标签: sorting methods smalltalk squeak


    【解决方案1】:

    简答:

    你不必这样做。

    要对数组进行排序,只需发送消息#asSortedCollection。例如,在工作区中检查:

    #(7 2 8 5) asSortedCollection
    

    长答案:

    因为我假设你想看看如果你真的不得不,你将如何在 Smalltalk 中实现你的 Java 代码的等价物,这里有一个相对“直译”你可以在工作空间中测试(在 Pharo 中测试,也应该在 Squeak 中工作):

    | someNumbers |
    someNumbers := #(7 2 8 5) copy. "See comments below for an explanation."
    someNumbers size to: 1 by: -1 do: [:eachOuterIndex |
        | indexOfSmallest swapValue |
        indexOfSmallest := 1.
        1 to: eachOuterIndex do: [:eachInnerIndex |
            (someNumbers at: eachInnerIndex) < (someNumbers at: indexOfSmallest)
                ifTrue: [ indexOfSmallest := eachInnerIndex ]
            ].
        swapValue := someNumbers at: indexOfSmallest.
        someNumbers at: indexOfSmallest put: (someNumbers at: eachOuterIndex).
        someNumbers at: eachOuterIndex put: swapValue.
        ].
    ^someNumbers
    

    显然,您的版本有一些变化,例如使用显式命名,这是 Smalltalk 的标志性约定之一(特别是,indexOfSmallest 应该比 first 更清晰,这是一种误导,因为它不一定是第一个索引),并减少您称为firsttemp 的变量的范围)。如果您在“翻译”方面遇到问题,请参阅@Leandro 对使用您自己的变量名的版本的回答。

    如果代码存在于方法中,我可能会将其放在SequenceableCollection 层次结构中(或者,如果您想覆盖其他行为,您可能希望将您的代码作为子类添加到其中),并且它的开头可能看起来像这样:

    copySortedDescending
        "Answer a copy of the receiver, sorted in descending order."
    
        | copy |
        copy := self copy.
        copy size to: 1 by: -1 do: [:eachOuterIndex |
            "... and so on..."
            ].
        ^copy
    

    再次,请注意我故意更改名称,因为我不认为 selectionSort 是该方法的描述性名称,并且我不会使用集合作为存在于某个地方的方法的参数else - 如何进行排序的知识属于集合本身

    不过,我相信您可以很容易地想出一个更好的自己动手的答案。例如,您可以尝试发送 SequenceableCollection 实例消息 sort: 并传递一个排序块作为参数,您可以在其中指定您希望如何对元素进行排序。

    【讨论】:

    • 您的代码大部分是正确的,但您不应该存储到文字数组中 (#(...))。大概把第一行改成someNumbers := #(7 2 8 5) copy.
    • @Tobias:就像我说的,它是 OP 代码的“字面翻译”。它在 Pharo 中按原样工作......为什么不改变它的值呢?我不是遍历数组,而是遍历索引。
    • 是的,没错。但是假设您在方法中编写此代码。您会期望每次调用它时,第一行都是相同的,但在第一次调用后情况并非如此。这有点复杂,所以我创建了一个社区 wiki 条目:stackoverflow.com/questions/29964345/…
    • @Tobias:我很欣赏你为表达你的观点所做的努力,这是一个相当棘手的案例——我在那里对你的问题和答案都投了赞成票。如果此代码 存在于方法中,而不仅仅是作为工作区示例,那么显然一开始就不会使用文字数组 - 数组将是参数,而方法将最可能“回答接收者的排序副本”。很高兴更新答案以包含copy,感谢您指出这一点。
    【解决方案2】:

    这里是逐行翻译。行号不是代码的一部分。

     1. selectionSort: num
     2.    | first temp |
     3.    num size to: 1 by: -1 do: [:i |
     4.        first := 1. "initialize to subscript of first element"
     5.        1 to: i do: [:j |
     6.            "locate smallest element between positions 1 and i"
     7.            (num at: j) < (num at: first) ifTrue: [first := j]].
     8.        temp := num at: first. "swap smallest with element in position i"
     9.        num at: first put: (num at: i).
    10.        num at: i put: temp]
    

    备注:

    1. 没有参数类型声明。没有答案类型。
    2. 在块内声明的临时块 ij(第 3 行和第 5 行)。在 Smalltalk 中,索引集合是基于 1 的。
    3. num.length() -> num size。减少for 循环将转换为to:by:do: 消息。
    4. 赋值 = 变为 :=0 变为 1(参见上面的第 2 行注释。)
    5. 增加for 循环将转换为to:do: 消息。
    6. 注释用双引号括起来。
    7. [j] 转换为 at: j 消息。 if 转换为 ifTrue: 消息。
    8. temp 可以在第一个块中声明:do: [:i | | temp |...
    9. num[j] = temp 也变成了发送at:put: 的消息。
    10. 同上 9。另请注意,您可以在第 9 行和第 10 行使用级联语法:

      num
          at: first put: (num at: i);
          at: i put: temp
      
    11. 不用回答num,因为已经被方法修改过了。然而,有趣的讨论源于 Amos 的回答:Why shouldn't I store into literal arrays in Smalltalk?

    【讨论】:

    • 谢谢!这非常清楚和有帮助!我改变了一点方式,但这一步一步解释了代码。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-07
    • 2019-06-23
    • 2020-01-06
    相关资源
    最近更新 更多