/**
* 快排
* 时间复杂度:平均时间复杂度为O(nlogn)
* 空间复杂度:O(logn),因为递归栈空间的使用问题
*/
def quickSort(list: List[Int]): List[Int] = list match {//使用模式匹配
case Nil => Nil//若列表为空则返回空列表
case head :: tail =>//若不为空
val (left, right) = tail.partition(_ < head)//见最下方解析“注1”
quickSort(left) ::: head :: quickSort(right)//左右两边分别递归调用quickSort方法,并且与head进行拼接。详见“注2”
}
注1:partition这个方法的使用举例:是将所有满足条件的放在左边,不满足条件的放在右边
注2:“:::”用于连接两个list集合;
“::”用于向队列的头部追加数据,创造新的列表。用法为 x::list,其中x为加入到头部的元素。
算法的核心:
1)快速排序事先选取一个元素作为用来比较的基准。比基准大的数放在右边,比基准小的数放在左边,一次分成大、小两类。
2)每一类又通过选取一个基准再次进行大小的分类。直到左右两边没有数据为止(递归即可)。
递归的解释:理解递归的关键在于先接受它。我们事先暗示自己“sort函数能够对输入的列表进行排序”。
按照这种暗示,我们进入sort函数体内,分成两种情况
1)如果传入的是Nil,则返回Nil——没错,sort对Nil进行的排序。
2)如果传入的不是Nil,sort会将列表ls分解成两个部分left和right,实际上还有首部tail。然后返回一个列表——这个列表由排序过的left+首部base+排序后的right。当然sort方法实现了它的承诺,返回的列表是排过序的。
先不要庆幸理解了快速排序,在这之后我们需要跳出这个暗示,说服自己为什么2)中的sort能够完成排序(这时候要把内部的自身调用看成另外一个函数)
合理的解释是sort能够把传入列表拆分成左右两个部分,然后使用一个拆分函数继续拆分,直到为Nil。这里的拆分函数还是sort,这个解释的重点在于“拆分”,而不是排序。换句话说,因为1)是可以被接受的,所以我们要从2)转到1)来给出sort能完成排序。