我需要在SML中实现快速排序以完成家庭作业,我迷路了。我以前不熟悉quicksort的实现方式,所以我读到了这一点,但我读到的每个实现都是强制性的。这些看起来并不太难,但我不知道如何在功能上实现quicksort。
维基百科碰巧在标准ML中使用快速排序代码(这是我的任务所需的语言),但我不明白它是如何工作的。
维基百科代码:
val filt = List.filter
fun quicksort << xs = let
fun qs [] = []
| qs [x] = [x]
| qs (p::xs) = let
val lessThanP = (fn x => << (x, p))
in
qs (filt lessThanP xs) @ p :: (qs (filt (not o lessThanP) xs))
end
in
qs xs
end
特别是,我不理解这一行:qs (filt lessThanP xs) @ p :: (qs (filt (not o lessThanP) xs))
。 filt将返回xs小于p *的所有内容的列表,该列表与p连接,后者包含在所有内容中&gt; = p。*
*假设&lt;&lt;当x 实际上,输入它可以帮助我理解发生了什么。无论如何,我正在尝试将该SML函数与wiki的快速排序伪代码进行比较,后面是。 function quicksort(array,'left','right') 其中分区定义为 那么,分区到底发生了什么?或者我是否错误地考虑了SMLs快速排序? // If the list has 2 or more items
if 'left' < 'right'
// See "Choice of pivot" section below for possible choices
choose any 'pivotIndex' such that 'left' ≤ 'pivotIndex' ≤ 'right'
// Get lists of bigger and smaller items and final position of pivot
'pivotNewIndex' := partition(array, 'left', 'right', 'pivotIndex')
// Recursively sort elements smaller than the pivot
quicksort(array, 'left', 'pivotNewIndex' - 1)
// Recursively sort elements at least as big as the pivot
quicksort(array, 'pivotNewIndex' + 1, 'right')
// left is the index of the leftmost element of the array
// right is the index of the rightmost element of the array (inclusive)
// number of elements in subarray = right-left+1
function partition(array, 'left', 'right', 'pivotIndex')
'pivotValue' := array['pivotIndex']
swap array['pivotIndex'] and array['right'] // Move pivot to end
'storeIndex' := 'left'
for 'i' from 'left' to 'right' - 1 // left ≤ i < right
if array['i'] < 'pivotValue'
swap array['i'] and array['storeIndex']
'storeIndex' := 'storeIndex' + 1
swap array['storeIndex'] and array['right'] // Move pivot to its final place
return 'storeIndex'
答案 0 :(得分:1)
你这样说:
filt将返回xs小于p *的所有内容列表,该列表与p连接,后者包含在所有内容中&gt; = p。*
这不太准确。 filt
将返回xs小于p
的所有内容的列表,但新列表不会立即与p
连接。实际上,新列表传递给qs
(递归),并且qs
返回的任何内容都与p
连接。
在伪代码版本中,分区在array
变量中就地发生。这就是您在swap
循环中看到partition
的原因。就地进行分区比制作副本要好得多。
答案 1 :(得分:1)
那么,分区到底发生了什么?或者我是否错误地考虑了SMLs快速排序?
快速排序的纯功能实现通过输入列表上的结构递归来工作(IMO,这值得一提)。此外,如您所见,两次调用“filt”允许您将输入列表分为两个子列表(比如A和B),然后可以单独处理。这里最重要的是:
通过交换同一数组中的元素,命令式实现就地工作。在您提供的伪代码中,“分区”函数的后不变量是您有两个子数组,一个从输入数组的“左”开始(以'pivotIndex'结尾),另一个从'pivotIndex'开始。 '并以'右'结束。这里重要的是两个子阵列可以看作是子列表A和B的表示。
我认为到目前为止,您已经了解了分区步骤的发生方向(或者反过来说,命令和功能是如何相关的)。