最近面试被问及次数最多的就是快排的算法,所以做了简单的梳理和实现,在此记录。
快排是利用分治法来对待排序序列,它的思想主要是定义一个基准值,之后通过一次排序将待排记录分隔成独立的两部分,基准值左边的数列都比基准值小,右边的数列都比基准值大,然后再对这两个数列分别采用这种方式进行排序,通过递归的方式最终使整个序列有序。
快速排序的一次划分算法从两头交替搜索,直到左右两个指针重合,因此其时间复杂度是O(n);而整个快速排序算法的时间复杂度与划分数列的次数有关。理想的情况是,每次划分所选择的中间数恰好将当前序列几乎等分,经过log2n趟划分,便可得到长度为1的子表。这样,整个算法的时间复杂度为O(nlog2n)。最坏的情况是,每次所选的中间数是当前序列中的最大或最小元素,这使得每次划分所得的子表中一个为空表,另一子表的长度为原表的长度-1。这样,长度为n的数据表的快速排序需要经过n趟划分,使得整个排序算法的时间复杂度为O(n2)。我们一般认为快排的时间复杂度是O(NlogN)。
快速排序不是稳定的排序算法,大小相同的两个数,经过快排后最终位置与初始位置有可能不同。当然也有可能相同(比如待排序记录中只有一组相同的数字,而选择的基数恰好是这组相同数字中的一个,此时的快速排序就是稳定的)
快排思路如下(转的):
我们从一个数组来逐步逐步说明快速排序的方法和思路。
假设我们对数组{7, 1, 3, 5, 13, 9, 3, 6, 11}进行快速排序。
首先在这个序列中找一个数作为基准数,为了方便可以取第一个数。
遍历数组,将小于基准数的放置于基准数左边,大于基准数的放置于基准数右边。
此时得到类似于这种排序的数组{3, 1, 3, 5, 6, 7, 9, 13, 11}。
在初始状态下7是第一个位置,现在需要把7挪到中间的某个位置k,也即k位置是两边数的分界点。
那如何做到把小于和大于基准数7的值分别放置于两边呢,我们采用双指针法,从数组的两端分别进行比对。
先从最右位置往左开始找直到找到一个小于基准数的值,记录下该值的位置(记作i)。
再从最左位置往右找直到找到一个大于基准数的值,记录下该值的位置(记作j)。
之后将两个坐标所指的元素进行交换,令较小的数字在左边,较大的数字在右边。
之后指针从之前i, j的位置继续向中间移动,即从j-1位置往前和i+1位置往后,重复上面比对基准数然后交换的步骤。
如果执行到i==j,表示本次比对已经结束,此时已经将数组全部比较了一遍。此时基准数base=[left]=最左面的数字,中位数=[i]/[j]。将最后i的位置的值与基准数做交换,此时基准数就找到了临界点的位置k,位置k两边的数组都比当前位置k上的基准值或都更小或都更大。
上一次的基准值7已经把数组分为了两半,基准值7算是已归位(找到排序后的位置)。
通过相同的排序思想,分别对7两边的数组进行快速排序,左边对[left, k-1]子数组排序,右边则是[k+1, right]子数组排序。
利用递归算法,对分治后的子数组进行排序。
Talk is cheap,直接show code(代码是自己写的):
/**
* @Auther: 杯酒暖天寒
* @Date: 2019-12-13 16:22
* @Description:实现快速排序
*/
public class QuickSort {
/**
* 快速排序实现
* @param numbers 待排序的数组
* @param left 基准值位置,一般选数组第一个元素
* @param right 数组最后一个元素的下标
*/
public static void quickSort(int [] numbers,int left,int right){
if (numbers ==null || numbers.length < 2 || left > right){
return;
}
int i = left;
int j = right;
int base = numbers[left];
while(i != j){
//从右往左找,找到比基准数小的数字,记录坐标
while (numbers[j] >= base && i < j ){
j--;
}
//从左往右找,找到比基准数字大的数字,记录坐标
while (numbers[i] <= base && i < j ){
i++;
}
//将找到的两个数字互换,得到新的数组
if (i < j){
int tmp = numbers[i];
numbers[i] = numbers[j];
numbers[j] = tmp;
}
}
//i = j时,基准数base = numbers[left],中位数 = numbers[i]
//将基准数和中位数互换,即基准数换到中位,分割成两个数列
numbers[left] = numbers[i];
numbers[i] = base;
//两个数列递归排序
quickSort(numbers, left, i-1);
quickSort(numbers, i+1, right);
}
public static void main(String[] args) {
int numbers[] = {7,1,3,5,13,9,3,6,11};
quickSort(numbers, 0, numbers.length-1);
System.out.print(Arrays.toString(numbers));
}
}