与合并排序一样,快速排序也是基于分治模式的。下面是对数组A[p…r]排序的分治过程的三个步骤:
分解:数组A[p…r]被划分为两个(可能空)的子数组A[p…q-1]和A[q+1…r],其中A[p…q-1]中的元素均小于A[q],A[q+1…r]中的元素均大于A[q]。
解决:通过递归调用快速排序,对子数组A[p…q-1]和A[q+1…r]进行就地排序
合并:因为两个子数组是就地排序的,将它们合并不需要操作。
简述一下快速排序的基本思想:在数组中选一个数作为轴中值(pivot),通过不断地比较将这个轴中值放在正确的位置上(左边的数比它小,右边的数比它大)。然后再递归地在左边的子序列和右边的子序列进行同样的操作,直到子序列的长度为1.
快速排序的思想很简单,但是通过上面的介绍可以看到两个问题:
1.轴中值(pivot)怎么选?
轴中值可以随便选。
在这篇博客里介绍两种选法:a)每次都选序列最后的元素 b)随机选择
2.怎么通过比较把轴中值放在合适的位置上?
先给这个操作取个名字:PARTITION,我们要向他传递三个参数:A,p,r.
A是数组名,p是子序列第一个元素,r是子序列最后一个元素。
在各种PATITION操作的讲解中,代码是最简单直白的,下面给出PATITION操作的Java代码:
static int partition(int[] a,int p,int r) {
int temp = a[r];
int i = p-1;
int swap = 0; //用于交换的临时变量
for(int j = p;j < r;j++) {
if(a[j]<temp) {
i++;
swap = a[i]; //交换,这里的交换用临时变量,因为可能要和自己做交换
a[i] = a[j];
a[j] = swap;
}
}
swap = a[i+1]; //交换
a[i+1] = a[r];
a[r] =swap;
return i+1;
}
下面以序列[13,19,9,5,12,8,7,4,21,2,6,11]为例展示PARTITON操作(轴中值取最后一个元素):