Recursion 用函数式语言实现快速排序
我需要在SML中为家庭作业实施快速排序,我迷路了。我以前不熟悉quicksort是如何实现的,所以我仔细阅读了这篇文章,但我读到的每一个实现都是必不可少的。这些看起来不太难,但我不知道如何在功能上实现快速排序 维基百科碰巧有标准ML格式的快速排序代码(这是我的作业所需的语言),但我不明白它是如何工作的 维基百科代码:Recursion 用函数式语言实现快速排序,recursion,functional-programming,sml,tail-recursion,ml,Recursion,Functional Programming,Sml,Tail Recursion,Ml,我需要在SML中为家庭作业实施快速排序,我迷路了。我以前不熟悉quicksort是如何实现的,所以我仔细阅读了这篇文章,但我读到的每一个实现都是必不可少的。这些看起来不太难,但我不知道如何在功能上实现快速排序 维基百科碰巧有标准ML格式的快速排序代码(这是我的作业所需的语言),但我不明白它是如何工作的 维基百科代码: val filt = List.filter fun quicksort << xs = let fun qs [] = [] | qs [x] = [x] | q
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
其中分区定义为
// 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'
//left是数组最左边元素的索引
//right是数组最右边元素的索引(包括)
//子阵列中的元素数=左+右+1
函数分区(数组、“左”、“右”、“数据透视索引”)
“pivotValue”:=数组['pivotIndex']
交换数组['pivotIndex']和数组['right']//将数据透视移动到末尾
'storeIndex':='left'
对于“i”,从“左”到“右”-1//左≤ 我是对的
如果数组['i']<'pivotValue'
交换数组['i']和数组['storeIndex']
'storeIndex':='storeIndex'+1
交换数组['storeIndex']和数组['right']//将轴移动到其最终位置
返回“storeIndex”
那么,分区到底发生在哪里呢?还是我对SMLs快速排序的想法是错误的?您说过:
filt将返回小于p*的xs中所有内容的列表,该列表与p连接,p连接到所有内容>=p*
这不太准确filt
将返回小于p
的xs中所有内容的列表,但新列表不会立即与p
连接。事实上,新列表被递归地传递给qs
,而qs
返回的任何内容都与p
连接在一起
在伪代码版本中,分区在数组
变量中发生。这就是为什么在分区
循环中会看到交换
。在适当的位置执行分区比创建副本更能提高性能
那么,分区到底发生在哪里呢?还是我错误地认为SMLs快速排序
quicksort的纯功能实现通过输入列表上的结构递归工作(IMO,这一点值得一提)。此外,正如您所看到的,对“filt”的两个调用允许您将输入列表划分为两个子列表(例如A和B),然后可以分别处理这两个子列表。重要的是:
- A的所有元素都小于或等于枢轴元素(代码中的“p”)
- B的所有元素都大于枢轴元素
我想现在你已经知道分区步骤发生在哪里了(或者反过来说,命令和功能是如何关联的)。感谢你澄清了我的误解。另外,我对SML代码中的分区发生在哪里感到困惑,而不是伪代码。抱歉,如果不清楚的话。@rob,@nate:“…filt将返回一个xs中小于p*的所有内容的列表,该列表与p连接,p连接到所有内容>=p.*”事实上,这不太正确。隐式括号是这样的:qs(filt-lessThanP-xs)@
(
p::(qs(filt(not o-lessThanP)xs)))
。不能将列表压缩到列表中,只能压缩单个元素。列表相互附加(@)。
// 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'