现在我们来思考下如何实现这样一种排序方式,若不考虑空间复杂度,我们最容易想到的一种方式是新建2个临时数组分别存放左右两部分排序的数据,比如临界值为4,我们将小于4的放到一个数组,大于4的放到另一个数组,然后将2个临时数组中的数据复制到原数组中即可,这样当循环往复完成后,数组中的所有元素就变成有序的了。但是这样排序的空间复杂度最大为O(n).
今天我们来说另一种空间复杂度为O(1)的操作,话不多说,我们直接上代码:
public static void quickSort(int arr[],int left,int right){
if(left>=right)return;
int q=partition(arr,left,right);
quickSort(arr,left,q-1);
quickSort(arr,q+1,right);
}
private static int partition(int[] arr, int left, int right) {
int sortIndex=left;
int arrIndex=left;
int pivot=arr[right];
while (arrIndex<right){
if(arr[arrIndex]<pivot){
int tmp=arr[arrIndex];
arr[arrIndex]=arr[sortIndex];
arr[sortIndex]=tmp;
sortIndex++;
}
arrIndex++;
}
arr[right]=arr[sortIndex];
arr[sortIndex]=pivot;
return sortIndex;
}
其中 arr 为待排序的数组,left 和 right 分别为arr 的左边界和右边界(若数组长度为6,则 left 和 right 分别为0和5),当 left 大于等于 right 时**,**达到终止条件直接返回。
现在我们来看下数组 6, 2, 3, 5, 1, 4 的快排执行过程,其中分治就是执行 partition 方法:
**6 2 3 5 1 4 left=0 right=5
第一次分治 2 3 1 4 6 5 left=0 right=5
第一次递归 2 3 1 left=0 right=2
第二次分治 1 3 2 left=0 right=2
第二次递归 left=0 right=0 left>=right,达到终止条件返回
第三次递归 3 2 left=1 right=2
第三次分治 2 3 left=1 right=2
第四次递归 left=1 right=0 left>=right,达到终止条件返回
第五次递归 left=2 right=2 left>=right,达到终止条件返回
第六次递归 6 5 left=4 right=5
第四次分治 5 6 left=4 right=5 left>=right,达到终止条件返回
第七次递归 left=4 right=3 left>=right,达到终止条件返回
第八次递归 left=5 right=5 left>=right,达到终止条件返回**
上面就是快速排序的详细执行过程了,是以数组的最后一个元素作为临界值进行快速排序的,可以看出当最后一次分治完成后数组就变成了1, 2, 3, 4, 5, 6 有序的了。
现在我们以上述数组的第一次分治为例,分析一下 partition 方法的执行过程: