快速排序
快速排序是一种分治的排序算法。它将一个数组分成两个子数组,将两部分独立地排序。快速排序和归并排序是互补的:归并排序将数组分成两个子数组分别排序,并将有序的子数组归并以将整个数组排序;而快速排序将数组排序的方式则是当两个子数组都有序时整个数组也就自然有序了。
证明
将长度为N的无重复数组排序,快速排序平均需要~2NlnN次比较(以及1/6的交换)
快速排序最多需要约N2/2 次比较,但随机打乱数组能够预防这种情况。
特点
1、实现简单,适用于各种不同的输入数据且在一般应用中比其他排序算法都要快得多。
2、它是原地排序(只需要一个很小的辅助栈),且将长度为N的数组排序所需的时间和NlgN成正比。
3、快速排序的内循环比大多数排序算法都要短小,这意味着它无论是在理论上还是在实际中都要更快。
public class QuickSort {
public void quickSortArray(int[] arr, int left, int right) {
int pivot = 0;
if (left < right) {
pivot = getPivot(arr, left, right);
System.out.println("key:" + arr[pivot] + ":" + Arrays.toString(arr));
quickSortArray(arr, left, pivot - 1);
quickSortArray(arr, pivot + 1, right);
}
}
public int getPivot(int[] arr, int left, int right) {
int key = arr[left];
while (left < right) {
while (left < right && arr[right] >= key) {
right--;
}
arr[left] = arr[right];
while (left < right && arr[left] <= key) {
left++;
}
arr[right] = arr[left];
}
arr[left] = key;
return left;
}
@Test
public void testSort() {
int[] ints = new int[]{1, 2, 5, 24, 34, 2, 234, 52, 24, 1, 42, 553, 52, 52, 2, 52, 55, 2};
//quickSortArray(ints,0,ints.length-1);
System.out.println("原始数据:" + Arrays.toString(ints));
quickSortArray(ints, 0, ints.length - 1);
System.out.println("排序数据" + Arrays.toString(ints));
}
}
过程示意图:
算法改进
切换到插入排序
和大多数递归排序算法一样,改进快速排序性能的一个简单办法基于以下两点:
1、对于小数组,快速排序比插入排序慢;
2、因为递归,快速排序的 sort() 方法在小数组中也会调用自己,因此在排序小数组时应该切换到插入排序。
三取样切分
1、改进快速排序性能的第二个办法是使用子数组的一小部分元素的中位数来切分数组。这样做得到的切分更好,但代价是需要计算中位数。
熵最优的排序
实际应用中经常会出现含有大量重复元素的数组,例如我们可能需要将大量人员资料按照生日排序,这个时候的快速排序性能还能接受,但是仍有将当前实现的线性对数级的性能提高到线性级别。