快速排序java实现
最近看《算法》看到了快速排序,书上原始的切分算法是这样的
1 | private static int partition(Comparable[] a, int lo, int hi) { |
这个算法存在许多的问题:
- 其选用的是数组的第一个元素作为切分元素。看一个极端情况:数组已是有序的。这时候切分元素每次取的都是最小的元素,每次只移除一个元素,这会导致一个大数组需要切分很多次,时间复杂度变为平方级别。
- 数组较小时,快速排序的效率低于插入排序。
算法的改进
对于第一个问题,可以使用取中位数法。
对于第二个问题,可以在数组元素低于某个值时,采用插入排序。
改进后的快速排序完整代码如下
1 | public class QuickSort implements Sort { |
Sort接口
1 | public interface Sort { |
插入排序算法
1 | public static void sort(Comparable[] a,int lo,int hi){ |
含大量重复元素的数组
当给定的数组中含有大量的重复元素时,原来的快速排序算法设定的是即使切分元素和比较元素相等时也会进行交换。虽然交换的次数较多,但是时间复杂度仍然保持在NlogN。原因是:
- 该算法每次排序会将相等元素数组平均分为两份,因此时间复杂度仍然为NlogN。
不过可以使用三向切分的快速排序来讲其复杂度降为N级别,代码如下
1 | public class Quick3way { |
这个算法的解决方案基于数组的从左到右传递,该数组保持指针lt使得a [lo..lt-1]小于v,指针gt使得a [gt + 1..hi ]大于v,并且指针i使得a [lt.i-1]等于v,而a [i..gt]尚未检查。
Quicksort 3路分区概述
从i等于lo开始, 我们使用Comparable接口给出的三向比较处理a [i]来处理三种可能的情况:
a [i]小于v:与a [i]交换a [lt]并同时增加lt 和i
a [i]大于v:将a [i]与a [gt]交换并减少gt
a [i]等于v:递增i
三向切分快速排序仅在数组中有大量重复元素时效率才高于普通的快速排序!