1 原理
1.1 步骤
在数组中任取一个元素作为枢纽元(pivot),将数组中除了枢纽元以外的元素划分成两个集合:一个集合 S1 中的元素大于枢纽元,另一个集合 S2 中的元素小于枢纽元。对两个集合分别进行 quicksort(递归),最后返回较小数集合+枢纽元+较大数集合的数组。
1.2 运行时间
平均运行时间为 O(N log N)
最长运行时间为 O(N^2)
1.3 枢纽元的选取
如果输入的数组不是随机的,就不应该选取第一个元素或最后一个元素作为枢纽元。如果输入的数组是预排序的或者反序的,那么所有元素都会被划分到 S1 或者 S2,而且之后的每次都是如此,花费的时间会是二次的。
一般使用三数中值分割法:即选择第一个元素,中间位置的元素和最后一个元素的中位数作为枢纽元。
2 实现
package chapter7.quicksort;
public class Quicksort {
private static final int MARK = 5;
public static void main(String args[]) {
int[] arr = {2, 243, 65, 2, 24, 66, 32,5,43,241,543,64578,6945,35765,8769,6980,7657,54,3,534,98,87,576,4,65353,435,34,564,64,56,56,5476,76,47,46754,6754,43,321,21,43,231,1,757,5654,432,4432,432,65,45,63,34,543,23,534,234,2,432,342,42,3,43,2,311,4,34,4235,65,47765,8,75,65,4243,234,452,3231,41,435,4365346,654,345,35235,3,564,6,541,1,1,1,1,1,1,1,1,1,1,1,2,3,3,43,3,2,2,4,22,3432,34,342,31,21,3,1342,43242,34,24,24,234,24,2, 6, 7, 8, 25, 32, 14, 54, 525, 354, 3, 5, 21, 765, 234, 64, 213, 32, 23, 876, 65, 9865, 564345, 2345};
long s=System.nanoTime();
arr = quicksort(arr);
long e=System.nanoTime();
print(arr);
System.out.println("time:"+(e-s)+"ns");
int[] arr1 = {2, 243, 65, 2, 24, 66, 32,5,43,241,543,64578,6945,35765,8769,6980,7657,54,3,534,98,87,576,4,65353,435,34,564,64,56,56,5476,76,47,46754,6754,43,321,21,43,231,1,757,5654,432,4432,432,65,45,63,34,543,23,534,234,2,432,342,42,3,43,2,311,4,34,4235,65,47765,8,75,65,4243,234,452,3231,41,435,4365346,654,345,35235,3,564,6,541,1,1,1,1,1,1,1,1,1,1,1,2,3,3,43,3,2,2,4,22,3432,34,342,31,21,3,1342,43242,34,24,24,234,24,2, 6, 7, 8, 25, 32, 14, 54, 525, 354, 3, 5, 21, 765, 234, 64, 213, 32, 23, 876, 65, 9865, 564345, 2345};
s=System.nanoTime();
arr1=sort(arr1);
e=System.nanoTime();
print(arr1);
System.out.println("time:"+(e-s)+"ns");
}
private static void print(int[] arr) {
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
/*快速排序*/
private static int[] quicksort(int[] arr) {
int length = arr.length;
int l = 0;
if (arr.length == 0) {
return null;
}
int position=0; //枢纽元位置
int[] pivotArr=new int[3];
pivotArr[0]=arr[0];
pivotArr[1]=arr[arr.length/2];
pivotArr[2]=arr[arr.length-1];
int[] newPivotArr=sort(pivotArr);
int pivot=newPivotArr[1]; //取枢纽元
if (pivot==pivotArr[0]){
position=0;
} else if (pivot==pivotArr[1]){
position=arr.length/2;
} else {
position=arr.length-1;
}
//int pivot = arr[0];
/*计算较小数集合的大小*/
for (int i = 0; i < length; i++) {
if (i==position){
continue;
}
if (arr[i] < pivot) {
l++;
}
}
int[] arrL = new int[l];
int arrR[] = new int[length - l - 1];
int countL = 0;
int countR = 0;
/*划分较大数集合和最小数集合*/
for (int i = 0; i < length; i++) {
if (i==position){
continue;
}
if (arr[i] < pivot) {
arrL[countL] = arr[i];
countL++;
} else {
arrR[countR] = arr[i];
countR++;
}
}
arr[position] = arr[countL];
arr[countL] = pivot; //确定枢纽元排序后的位置
/*集合中元素个数大于3,使用quicksort,否则用冒泡排序*/
if (countL > MARK) {
arrL = quicksort(arrL);
} else {
arrL = sort(arrL);
}
if (countR > MARK) {
arrR = quicksort(arrR);
} else {
arrR = sort(arrR);
}
/*把两个集合与枢纽元拼接起来*/
for (int i = 0; i < countL; i++) {
arr[i] = arrL[i];
}
for (int i = countL + 1; i < length; i++) {
arr[i] = arrR[i - countL - 1];
}
return arr;
}
/*冒泡排序*/
private static int[] sort(int[] arr) {
int[] newArr=new int[arr.length];
for (int i=0;i<arr.length;i++){
newArr[i]=arr[i];
}
for (int i = 0; i < newArr.length - 1; i++) {
for (int j = 0; j < newArr.length - 1 - i; j++) {
if (newArr[j] > newArr[j + 1]) {
int temp = newArr[j];
newArr[j] = newArr[j + 1];
newArr[j + 1] = temp;
}
}
}
return newArr;
}
}