面试:快速排序

快排,排序算法,对包含n个数的输入数组,最坏情况运行时间为O(n2)。快排通常是用于排序的最佳实用选择,平均性能相当好时间复杂度为O(nlogn),且O(nlogn)记号中隐含的常数因子很小。

时间复杂度:O(NlogN); 空间复杂度:O(1)

1. 一个典型子数组A[p..r]排序的分治过程的三个步骤

  • 分解:数组A[p..r]被划分成两个(可能空)子数组A[p..q-1]和A[q+1..r],使得A[p..q-1]中的每个元素都<=A[q],下标q在划分过程中进行计算。
  • 解决:递归调用快速排序,对子数组A[p..q-1]和A[q+1..r]排序。
  • 合并:两个子数组是就地排序的,因此不需要合并操作:整个数组A[p..r]已经排序。

2.实现快速排序

1 QUICKSORT(A, p, r )
2     if p<r
3         then q ← PARTITION(A, p, r )
4                 QUICKSORT(A, p, q-1)
5                 QUICKSORT(A, q+1, r)

排序一个完整的数组A,最初的调用是QUICKSORT(A, 0, length[A]-1)。(《算法导论》P85有误)

3.快速排序算法的关键是PARTITION过程

它对子数组A[p..r]进行就地重排。

关键变量:

  • x:待排序子数组右边界的值
  • i:数组下标 i 左边的数(包括i)小于x的值
  • j:遍历位置p..r-1的下标
1 PARTITION(A, p, r)
2     x ← A[r]
3     i ← p-1
4     for j←p to r-1
5            do if A[j] <= x
6                 then i ← i+1
7                     exchange(A[i], A[j])    
8     exchange(A[i+1], A[r])
9     return i+1

4.更上一层楼

理解上面的过程,请看《算法导论》P86的演示算法过程-PARTITION

4.1 Java中Arrays.sort(int[])的排序:一种经过调优的快速排序

  1. 优化1:在小规模(size<7)数组中,直接插入排序的效率要比快速排序高。  
  2. 优化2:精心选择划分元素,即枢轴(最基本的快排是选取数组的最后一个元素)
  • 如果是小规模数组(size<=7),直接取中间元素作为枢轴
  • 如果是中等规模数组(7=<size<=40),则在数组首、中、尾三个位置上的数中取中间大小的数作为枢轴
  • 如果是大规模数组(size>40),则在9个指定的数中取一个伪中数(中间大小的数s)
  1. 优化3:与枢轴相等的元素移动到一起,排序枢轴两边的部分。这对于重复元素多的数组是一个极大的优化。

4.2 对象数组的排序,如Arrays.sort(Object[])等。采用了一种经过修改的归并排序

  1. 优化1:在小规模(size<7)数组中,直接插入排序的效率要比归并排序高。
  2. 优化2:如果低子列表中的最高元素小于高子列表中的最低元素,则忽略合并。 这个优化措施无疑对基本有序序列是极大的效率改进。

posted on 2014-09-23 19:25  BYRHuangQiang  阅读(2201)  评论(1编辑  收藏  举报

导航