参考:https://www.cnblogs.com/onepixel/articles/7674659.html
其他排序算法传送门:https://blog.csdn.net/jkdcoach/article/details/87442482
源码:https://github.com/sunrui849/sort
快速排序
快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
1.1 算法描述
快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:
- 从数列中挑出一个元素,称为 “基准”(pivot);
- 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
- 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
1.2 动图演示
1.3特性
采用分治思想,理想情况下不断将数组分成两部分进行排序,平均时间复杂度为n*(log n),最坏为n*n
n*n:每一个选取的基准点都为当前区间最大或最小时,比较的次数即 (n-1) + (n-2) +...+1 = (n-1)*n/2 ,时间复杂度为n*n
n*(log n):比较的次数用 T表示
T(n) = 2*T(n/2) + n
=2*(2*T(n/4) + n/2) +n= 4*T(n/4) +2*n
=4*(2*T(n/8) + n/4) + 2*n = 8*T(n/8) + 3*n...
当n=1时为0 T(1)=0, 结果为n*T(1)+(log n)n ,所以时间复杂度为n*(log n)
1.4代码实现
/**
* 从小到大
* 快速排序
* 初始化
* @param arr
* @return
*/
public static int[] sort(int[] arr) {
if (arr == null || arr.length == 0){
return arr;
}
return quickSort(arr,0,arr.length-1);
}
/**
* 递归排序两段数组
* @param arr
* @param left
* @param right
* @return
*/
private static int[] quickSort(int[] arr, int left, int right) {
if (left >= right) {
return arr;
}
int middleIndex = sortMiddle(arr,left,right);//找个基准值并使基准值左侧小右侧大,返回基准值索引
quickSort(arr,left,middleIndex-1);//排序左区间
quickSort(arr,middleIndex+1,right);//排序右区间
return arr;
}
/**
* 排序区间数据,使选定值两侧分别为大或小
* 左右闭区间
* @param arr
* @param left
* @param right
* @return
*/
private static int sortMiddle(int[] arr,int left, int right){
int sureValue = arr[left];//基准值
int index = left +1;//这个标记右边为比选定值大的,左边为比选定值小的,相当于左区间上限+1
for (int i = index; i <= right; i++){
if (arr[i] < sureValue){//比基准值小则交换到左区间
swap(arr,index,i);
index++;//左区间上限+1
}
}
swap(arr,left,index-1);//使基准值与左区间上限替换
return index-1;
}
/**
* 交换位置
* @param arr
* @param i
* @param j
*/
private static void swap(int[] arr,int i,int j) {
int flag = arr[i];
arr[i] = arr[j];
arr[j] = flag;
}