一、源代码
def msort[T](xs:List[T])(lt: (T,T) => Boolen):List[T]={
val n = xs.length / 2
if ( n == 0 ) xs
else{
def merge(xs: List[T],ys: List[T]):List[T] = (xs, ys) match{
case(Nil, ys) => ys
case(xs, Nil) => xs
case(x:: xs1,y:: ys1)=>
if(lt(x,y)) x::merge(xs1,ys)
else y:: merge(xs,ys1)
}
val (fst,snd) = xs splitAt n
merge(msort(fst)(lt),msort(snd)(lt))
}
}
源代码来自Coursera 《Scala函数式编程原理》
其中,msort函数的第二个参数——lt: (T,T) => Boolen,它是一个自定义的谓词比较方法,用于比较T类型对象的大小,这里不做讨论。
二、示例
List元素:ls : List[Int]={7,4,15,43,9}
msort({7,4,15,43,9})
merge(msort({7,4,15}),msort({43,9}))
对于msort({7,4,15})的递归
=>merge(msort({7,4}),msort({15}))
对于msort({7,4})的递归
=>merge(msort({7}),msort({4}))
=>merge(7,4)
对于msort({43,9})的递归
=>merge(msort({43}),msort({9}))
=>merge(43,9)
merge(merge(msort({7,4}),msort({15})),merge(msort({43}),msort({9})))
merge(merge(merge(msort({7}),msort({4})),15),merge(43,9))
merge(merge(merge(7,4),15),merge(43,9))//这是一系列的拆分过程
拆分的图示:
上面是一个拆分过程,之后进行列表的两两合并:
每次合并后,都会形成有序的列表,所以问题转化成了——对两个有序的列表进行排序。回顾merge函数,它借用msort对参数进行分解。也就是说merge函数的两个列表参数一定是有序的——在merge函数体内,就是对两个列表有序列表进行合并排序的过程。
三、原理
1.将待排序的列表拆分成包含单个元素的列表
2.拆分的列表元素列表两两合并并排序,直到合并成一个列表。
四、递归函数的输入和输出
1. msort函数:传入一个待排序列表,输出一个排序后的列表。
2.merge函数:传入两个有序的列表,输出一个有序的列表。
五、递归的解释
程序中出现的递归有这几处:
1.merge函数的参数使用msort做了拆分的递归操作。
2.merge对两个参数进行排序使用了merge函数。这里的递归更像一种功能的重用——合并两个有序列表的功能。
递归的退出条件:
1.msort函数:待排序的列表只有一个元素或者为空列表
2.merge函数:两个参数中有一个为空列表
递归部分的处理:
msort使用merge函数返回一个有序列表
merge使用merge函数自身将两个有序列表进行合并
很明显,递归交由merge函数处理,也就是说,merge能够达到自身退出递归的条件—— 一直调用merge函数会形成,参数中只有一个列表的情况。所以,这里的msort函数只是提供了一个拆分的功能——辅助merge函数,将一个列表折半成两个列表的功能。
目前为止,重点就是merge函数合并两个有序列表的方法,这里通过提取出最小的一个元素,并merge剩下的元素来缩减,针对{4,7,15}和{9,43}的merge函数的递归合并过程如下图:
这就实现了对两个有序列表进行排序的过程。对于归并排序的总结就是两点:
1.使用msort对待排序的列表进行拆分,直到形成含单个元素的列表。
2.使用merge对两个有序列表进行合并,直到形成一个列表为止。