快速排序是交换类的排序,比如在站队的时候,老师说:“第一个同学出列,其他同学以第一个同学为中心,比他矮的全排在左边,比他高的全排在右边。”这就是一趟快速排序。可以看出,一趟快速排序是以一个“枢轴”为中心,将序列分成两个部分,枢轴的一边全是比它小(或者小于等于)的,另一边则全是比它大(或者大于等于)的。
快速排序算法采用了一种分治的策略,通常称其为分治法,其基本思想是:
1、先从数列中取出一个数作为基准数;
2、分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边;
3、再对左右区间重复第二步,直到各区间只有一个数。
以一个简单的数组为例,我们来看一下,快速排序算法的排序过程:
再对array[0…1]和array[3..4]重复上述操作步骤就行了。
注意:在一次查找中只有i和j的值在变,X的值是一直保持不变的。
以上步骤总结为:
1、i=l,j=r,x=array[i];
2、j- -从后向前找小于等于x的数,找到后用array[j]替代array[i];
3、i++从前向后找大于x的数,找到后用array[i]替代array[j];
4、一直重复执行2、3步骤,直到i=j为止,最后将基准数写入array[i]。
算法实现如下:
int quickSort(int s[], int l, int r){
int i = l, j = r;
int x = s[l]; //s[l]即s[i]为基准数/枢轴
while (i < j){
// 从右向左找小于x的数来替换s[i]
while(i < j && s[j] >= x) {
j--;
}
if(i < j){
s[i] = s[j];
i++;
}
// 从左向右找大于或等于x的数来替换s[j]
while(i < j && s[i] < x){
i++;
}
if(i < j){
s[j] = s[i];
j--;
}
}
//退出时,i等于j。将基准数填到这个位置上。
s[i] = x;
//返回调整后基准数的位置
return i;
}
java代码实现如下:
public class quickSortDemo {
public static void quickSort(int[] array, int left,int right){
if (left < right){
int i = left, j = right, x = array[left];
//从右向左找第一个小于x的数放到array[i]中
while (i < j){
while(i < j && array[j] >= x){
j--;
}
if(i < j){
array[i] = array[j];
i++;
//等价于array[i++] = array[j]
}
//从左向右找第一个大于等于x的数放到array[j]中
while(i < j && array[i] < x){
i++;
}
if(i < j){
array[j] = array[i];
j--;
//等价于array[j--] = array[i]
}
}
array[i] = x;
//递归调用
quickSort(array, left, i - 1);
quickSort(array, i + 1, right);
}
}
public static void main(String[] args) {
int[] array = {2,7,9,3,5,6,1,8};
quickSort(array,0,7);
for (int k = 0; k < array.length; k++) {
System. out.println(array[k]);
}
}
}
时间复杂度:
快速排序算法最好情况下的时间复杂度为O(N*logN){以2为底数},待排序序列越接近无序,算法效率越高。最坏情况下的时间复杂度为O(N2){n的平方},待排序序列越接近有序,算法效率越低。平均时间复杂度为O(N***logN){以2为底数}**。就平均时间而言,快速排序算法是所有排序算法中最好的快速排序的排序趟数和初始序列有关。
空间复杂度:
快速排序算法的空间复杂度为O(logN){以2为底数},快速排序是递归进行的,递归需要栈的辅助,因此快速排序算法需要的辅助空间比其他的排序算法多。