算法思想
快速排序(Quicksort)是对冒泡排序的一种改进,借用了分治的思想,由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
实现过程
1:从当前数组中取出一个元素作为一个基准值
2:从数组的后面开始往前取值和这个基准值对比,比它小就放到这个基准值的位置
3:从数组的前面开始取值和这个基准值对比,比它大就放到这个基准值后面
4:重复2,3操作直到往前找不到比它大的,往后找不到比它小的
5:进行递归调用
代码实现
第一种方法(称为挖坑法)
/**
* ClassName:QuickSort1
* Author:LFM
* Date:2019/6/15 16:04
**/
public class QuickSort1 {
public static void sort(int [] arr, int low,int high){
if (arr==null||arr.length<=0){
return ;
}
if (low>=high){
return;
}
int left = low;
int right = high;
int temp = arr[left];//挖坑1,保存这个基准值(假设是第一个元素)
while (left<right){
while (left<right && arr[right]>=temp){
right--;//从后往前移逐步寻找比基准值小的数(相对于基准值)
}
arr[left] = arr[right];//挖坑2:从后向前找到比基准值小的元素,插入基准值位置坑1中
while (left<right && arr[left]<=temp){
left++;//从前往后逐步寻找比基准值大的数(相对于基准值)
}
arr[right] = arr[left];//挖坑3:从前向后找比基准值大的数,放到坑2中。
}
arr[left] = temp;//当left==right时(说明找到自己了,即后无小,前无大),将基准值放入坑3中,准备分治递归快排
System.out.println("排序...:"+ Arrays.toString(arr));
sort(arr,low,left-1);//这个就是做基准值左部分的排序(-1的目的就是除去基准值的位置)
sort(arr,left+1,high);//这个就是基准值右部分的排序(+1也是同样道理,但是这里用high就是保证这右边的长度是除去基准值和左边后的长度)
}
public static void main(String[] args) {
int [] arr = {4,3,7,5,10,9,1,6,8,2};
System.out.println("排序前:"+Arrays.toString(arr));
sort(arr,0,arr.length-1);
}
}
运行结果
详细解释我都写在代码的注释里面了,唯一要解释的就是调用的时候要把数组的长度-1,因为我们取了一个元素作为基准值了。
第二种方法(左右指针法)
/**
* ClassName:QuickSort2
* Author:LFM
* Date:2019/6/15 18:06
**/
public class QuickSort2 {
public static void sort2(int arr[], int low, int high) {
if (arr == null || arr.length <= 0) {
return;
}
if (low >= high) {
return;
}
int left = low;
int right = high;
int key = arr[left];//相当于挖坑操作,选定一个基准值
while (left < right) {
while (left < right && arr[right] >= key) {
right--;//从后往前找,符合之后记录right值
}
while (left < right && arr[left] <= key) {
left++;//从前往后找,符合之后记录left值
}
if (left < right) {
swap(arr, left, right);//交换数组下标和达到交换数组元素,这种方法就是把第一种占坑操作综合起来了
}
}
swap(arr, low, left);//交换基准值和当前left=right的那个位置的元素
System.out.println("排序后: " + Arrays.toString(arr));
sort2(arr, low, left - 1);
sort2(arr, left + 1, high);
}
public static void swap(int arr[], int low, int high) {
int tmp = arr[low];
arr[low] = arr[high];
arr[high] = tmp;
}
public static void main(String[] args) {
int [] arr = {4,3,7,5,10,9,1,6,8,2};
System.out.println("排序前:"+Arrays.toString(arr));
sort2(arr,0,arr.length-1);
}
}
运行结果:
这种方法就是把通过交换数组的下标来交换元素,同时把元素之间的交换操作通过一个自定义函数完成。看上去比较简洁把,算法思想是一样的
时间复杂度
快速排序是不稳定的,因为每次交换的元素可能不是相邻
这个时间复杂度比较难理解,我看别人是这么推算的:
现在我还不会,也想不明白(数学不太好、时间不够了,等我工作时买了算法导论再来写一个详细的证明过程,现在先记住先)