一、一个思想
一个乱序的数组中每一个数字的位置的都是固定的,也就是排序乱序的数组中每一个数字都是对应了一个固定的下标。例如
int[] arr = {1,2,3,4,5};//其中的1无论怎么打乱这个数组,再次排序,小标为0 的元素一定是1
快速排序的思想就是选定一个基准值,然后找到其固定的位置,然后递归求出。
二、两个方法
(1)基准值在两端
private static void rightQucikSort(int[] arr, int start, int end) {
if(start<end){ //递归终止条件
int low = start;
int high = end;
int standard = arr[high];//基准值
while (low<high){
while (low<high&&arr[low]<standard)low++;
if(low<high)arr[high--]=arr[low];
while (low<high&&arr[high]>standard)high--;
if(low<high)arr[low++]=arr[high];
}
arr[high]=standard; //找到基准值在数组中固定的位置
rightQucikSort(arr, start, high-1);
rightQucikSort(arr, high+1, end);
}
}
(2)基准值在中间(一般取最中间的值)
private static void middleQucikSort(int[] arr, int start, int end) {
if(start<end){ //递归结束条件
int standard = arr[(start+end)>>1]; //基准值
int low = start-1; //交换方便
int high = end+1;
while (low<high){
while (low<high&&arr[++low]<standard);
while (low<high&&arr[--high]>standard);
int temp = arr[low]; //交换
arr[low]=arr[high];
arr[high]=temp;
}
middleQucikSort(arr, start, low-1);
middleQucikSort(arr, high+1, end);
}
}
三、总结
(1)快速排序的一次划分算法从两头交替搜索,直到low和high重合,因此其时间复杂度是O(n);而整个快速排序算法的时间复杂度与划分的趟数有关。
(2)理想的情况是,每次划分所选择的中间数恰好将当前序列几乎等分,经过log2n趟划分,便可得到长度为1的子表。这样,整个算法的时间复杂度为O(nlog2n);最坏的情况是,每次所选的中间数是当前序列中的最大或最小元素,这使得每次划分所得的子表中一个为空表,另一子表的长度为原表的长度-1。这样,长度为n的数据表的快速排序需要经过n趟划分,使得整个排序算法的时间复杂度为O(n2)。
(3)不过,可以证明快速排序的平均时间复杂度也是O(nlog2n)