快速排序是一种效率很高的排序方法,在做题的过程中经常用到,面试的时候也是一个高频考点,决定对快速排序做个小结。本文参考了文章白话经典算法系列之六 快速排序 快速搞定以及我见过最通俗易懂的快速排序过程讲解,转自《坐在马桶上看算法:快速排序》。这两篇文章对快速排序做了通俗易懂的讲解,看完之后收获很大。
快速排序的思想:
先选取数组中的一个数,使这个数左边的数都比它小,右边的数都比它大(假设按升序排列),那么这个数就到了最终的正确位置上了。再分别对左边和右边的子序列进行排列,利用递归,直到子序列只有一个数,把这个数放在正确位置上。当所有的数都处在正确位置上时,排序完成。
实现方法:
如何使一个数它左边的数都比它小,右边的数都比它大呢?有两种方法,一种是交换法,一种是挖坑法。
(1)交换法:
选取数组a最左边的元素x,从数组最右边开始找,碰到第一个比x小的元素时停下,把下标记为j,再从数组的左边(第二个元素)开始找,碰到第一个比x大的元素时停下,把下标记为i,交换a[i]和a[j],然后j减一,i加一。下一次分别从j往左找,再从i往右找,重复上述过程,直到i和j碰面为止,将a[i]与第一个元素x交换。
(2)挖坑法:
选取数组a最左边元素x,用key把x的值保留下来,相当于在a[0]这个地方挖了一个坑,从数组最右边开始找,碰到第一个比x小的元素时停下,把下标记为j,把a[j]挖走填到a[0],a[j]这个地方就空出来一个坑,再从数组的最左边开始找,碰到第一个比x大的元素时停下,把下标记为i,把a[i]挖走填到a[j],a[i]这个地方就空出一个坑。以此类推,最后i和j相等时把key保存的值填到a[i]。
代码
(1)交换法
public class Main {
public static void main(String[] args) {
int[] a=new int[10];
Scanner in=new Scanner(System.in);
for(int i=0;i<a.length;i++){
a[i]=in.nextInt();
}
quickSort(a,0,a.length-1);
for(int n:a){
System.out.print(n+" ");
}
}
private static void quickSort(int a[],int l,int r){
if(l>r){
return;
}
int i=l,j=r;
int key=a[l];
while(i<j){
while(i<j&&a[j]>=key){
j--;
}
while(i<j&&a[i]<=key){
i++;
}
if(i<j){
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
a[l]=a[i];
a[i]=key;
quickSort(a,l,i-1);
quickSort(a,i+1,r);
}
}
(2)挖坑法:
public class Main {
public static void main(String[] args) {
int[] a=new int[10];
Scanner in=new Scanner(System.in);
for(int i=0;i<a.length;i++){
a[i]=in.nextInt();
}
quickSort(a,0,a.length-1);
for(int n:a){
System.out.print(n+" ");
}
}
private static void quickSort(int a[],int l,int r){
if(l>r){
return;
}
int i=l,j=r;
int key=a[l];
while(i<j){
while(i<j&&a[j]>=key){
j--;
}
a[i]=a[j];
while(i<j&&a[i]<=key){
i++;
}
a[j]=a[i];
}
a[i]=key;
quickSort(a,l,i-1);
quickSort(a,i+1,r);
}
}
备注
如果数组是已经有序或者已经部分有序,选取数组最左边的元素作为把数组一分为二的元素就没有那么有效率了,因为元素已经处在正确的位置上了,可以考虑随机选取一个元素来把数组一分为二,使这个数左边的数都小于它,右边的数都大于它。