挖坑法
挖坑法,可以理解成拆东墙补西墙。这里以数组[4,1,7,6,9,2,8,0,3,5]为例子讲解。以数据第一个元素作为枢轴(也可以是最后一个,看你喜好)。
这里我们先把作为枢轴的4抠出来单独放置,此时数组变成了
[口,1,7,6,9,2,8,0,3,5]
这时我们要从数组尾部开始往前找,找第一个比4小的数字,5比4大,j - -,这时3比4小,把3放在坑里。因为把3抠出来补坑里了,因此3原来所在的位置又变成了一个坑。
[3,1,7,6,9,2,8,0,口,5]
这时候我们要从数组头部开始往后找,找第一个比4大的数字,1比4小,i + +,这时7比4大,把7放在坑里。这时,7原来的位置又变成了坑。
[3,1,口,6,9,2,8,0,7,5]
接着从数组右边开始找比4小的数,0比4小,把0抠出来放在坑里。0原来的位置又变成了坑。
[3,1,0,6,9,2,8,口,7,5]
接着从数组左边开始找比4大的数字,6比4大,把6抠出来放在坑里。6原来的位置又变成了一个坑。
[3,1,0,口,9,2,8,6,7,5]
接着从右边开始找比4小的数字,8不比4小,j - -,这时2比4小,把2抠出来放在坑里。2原来的位置变成了坑。
[3,1,0,2,9,口,8,6,7,5]
接着从数组左边找比4大的数字,9比4大,把9放进坑里。9原来的位置变成了坑。
[3,1,0,2,口,9,8,6,7,5]
此时i==j,即游标重叠了。这时,我们将一开始取出来的枢轴4放进最后这个坑里。这就完成了第一趟快排。
[3,1,0,2,4,9,8,6,7,5]
你会发现枢轴4左边的数字都比4小,4右边的数字都比4大。
接下来[3,1,0,2]和[9,8,6,7,5]分别都采用这样的挖坑法进行排序。一直到数组只包含一个数字为止,便完成了最终的排序。
public class Test {
static void quicksort(int s[],int left,int right){
if(left<right){
int temp=s[left],i=left,j=right;
//寻找右边第一个小于基准值的下标
while(s[j]>=temp&&i<j)j--;
if(i<j) {s[i]=s[j];i++;}
//寻找左边第一个大于基准值的下标
while(s[i]<=temp&&i<j)i++;
if(i<j) {s[j]=s[i];j--;}
s[i]=temp;//当游标指针i和j重叠时将枢轴填入坑
System.out.println("-----枢轴:"+temp);
quicksort(s,left,i-1); //递归左边部分数组
quicksort(s,i+1,right); //递归右边部分数组
}
}
public static void main(String[] args) {
int []a= {4,1,7,6,9,2,8,0,3,5};
quicksort(a,0,9);
for(int i:a) {
System.out.println(i);
}
}
}
输出:
—–枢轴:4
—–枢轴:3
—–枢轴:2
—–枢轴:0
—–枢轴:9
—–枢轴:5
—–枢轴:8
—–枢轴:7
0
1
2
3
4
5
6
7
8
9
左右指针法
思想:
1、选取一个关键字(key)作为枢轴,一般取整组记录的第一个数/最后一个为枢轴。
2、设置两个变量left = 0;right = N - 1;
3、从left一直向后走,直到找到一个大于key的值,right从后至前,直至找到一个小于key的值,然后交换这两个数。
4、重复第三步,一直往后找,直到left和right相遇,这时将key放置left的位置即可。
这里还是以[4,1,7,6,9,2,8,0,3,5]为例做解释。这里以第一个元素4作为枢轴。right向前找比4小的数,此时3比4小,left向后找比4大的数,此时7比4大,交换3和7;
[4,1,3,6,9,2,8,0,7,5]
right向前找比4小的数,此时0比4小,left向后找比4大的数,此时6比4大,交换0和6;
[4,1,3,0,9,2,8,6,7,5]
right向前找比4小的数,此时2比4小,left向后找比4大的数,此时9比4大,交换2和9;
[4,1,3,0,2,9,8,6,7,5]
这时将枢轴4和array[left]的值进行一次交换,就完成了第一趟快排。
[1,3,0,2,4,9,8,6,7,5]
快慢指针法
思想:
针对取最后一个元素作为枢轴的情况:
1、定义变量fast指向序列的开头,定义变量slow的前一个位置。
2、当array[fast] < key时,fast和slow同时往后走,如果array[fast]>key,fast往后走,slow留在大于key的数值前一个位置。
3、当array[fast]再次 < key时,交换array[fast]和array[slow]。
说白了就是,在没找到大于key值前,slow永远紧跟fast,遇到大于枢轴的值,两者之间就会拉开差距,中间差的肯定是连续的大于key的值,当再次遇到小于key的值时,交换两个下标对应的值就好了。
这里还是以[4,1,7,6,9,2,8,0,3,5]为例做解释。这里取5作为枢轴。
从数组左边开始找比5大的数字,4不比5大,fast++,slow++,1不比5大,fast++,slow++,此时fast指向7,slow指向1。这时,7比5大,fast++,slow不动,此时,fast指向的6仍比5大,fast++,slow仍不动,此时fast指向的9比5大,fast++,slow不动。此时fast指向的2比5小,则这时候slow++,指向7。此时,交换fast指向的2和slow指向的7。
[4,1,2,6,9,7,8,0,3,5]
接着,往后遍历,fast++,fast指向8,比5大,slow不动,fast++,fast指向0,0比5小,此时slow++,slow指向6。这时候,交换fast指向的0和slow指向的6。
[4,1,2,0,9,7,8,6,3,5]
接着,往后遍历,fast++,fast指向3,比5小,slow++,slow指向9,此时,将fast指向的3和slow指向的9交换。
[4,1,2,0,3,7,8,6,9,5]
最后,将枢轴5赋值给array[slow]。
[4,1,2,0,3,5,7,8,6,9]