作为starblue already said,您需要一个函数来计算列表的最小值并返回删除该元素的列表。这是我对类似东西的尾递归实现(我相信foldl 在标准库中是尾递归的),我试图让它尽可能地实用:)。它返回一个列表,其中包含原始列表的所有元素(但有点颠倒 - 请参阅下面的解释),其中最小值作为头部。
def minimum(xs: List[Int]): List[Int] =
(List(xs.head) /: xs.tail) {
(ys, x) =>
if(x < ys.head) (x :: ys)
else (ys.head :: x :: ys.tail)
}
这基本上是折叠,从包含xs 第一个元素的列表开始如果xs 的第一个元素小于该列表的头部,我们将其预先附加到列表ys .否则,我们将其添加到列表 ys 作为第二个元素。以此类推,我们将列表折叠成一个新列表,其中包含最小元素作为头部,另一个列表包含xs 的所有元素(不一定以相同的顺序),并移除最小值作为尾部。请注意,此函数不会删除重复项。
创建此辅助函数后,现在很容易实现选择排序。
def selectionSort(xs: List[Int]): List[Int] =
if(xs.isEmpty) List()
else {
val ys = minimum(xs)
if(ys.tail.isEmpty)
ys
else
ys.head :: selectionSort(ys.tail)
}
不幸的是,这个实现不是尾递归的,所以它会炸毁大列表的堆栈。无论如何,您不应该对大型列表使用 O(n^2) 排序,但是......如果实现是尾递归的,那就太好了。我会想办法……我认为它看起来像是折叠的实现。
尾递归!
为了让它成为尾递归,我在函数式编程中使用了一种非常常见的模式——累加器。它的工作有点落后,因为现在我需要一个名为maximum 的函数,它基本上与minimum 相同,但具有最大元素 - 它的实现与最小值完全相同,但使用> 而不是< .
def selectionSort(xs: List[Int]) = {
def selectionSortHelper(xs: List[Int], accumulator: List[Int]): List[Int] =
if(xs.isEmpty) accumulator
else {
val ys = maximum(xs)
selectionSortHelper(ys.tail, ys.head :: accumulator)
}
selectionSortHelper(xs, Nil)
}
编辑:将答案更改为具有辅助功能作为选择排序功能的子功能。
它基本上将最大值累积到一个列表中,最终将其作为基本情况返回。您还可以通过将 accumulator 替换为 throw new NullPointerException 来查看它是尾递归的 - 然后检查堆栈跟踪。
这里是使用累加器的分步排序。左侧显示列表xs,而右侧显示accumulator。最大值在每一步用星号表示。
64* 25 12 22 11 ------- Nil
11 22 12 25* ------- 64
22* 12 11 ------- 25 64
11 12* ------- 22 25 64
11* ------- 12 22 25 64
Nil ------- 11 12 22 25 64
下面展示了一步一步的折叠计算最大值:
maximum(25 12 64 22 11)
25 :: Nil /: 12 64 22 11 -- 25 > 12, so it stays as head
25 :: 12 /: 64 22 11 -- same as above
64 :: 25 12 /: 22 11 -- 25 < 64, so the new head is 64
64 :: 22 25 12 /: 11 -- and stays so
64 :: 11 22 25 12 /: Nil -- until the end
64 11 22 25 12