这是一种基于二分的排序算法,原理简单易懂,但是之前纠结与算法语言的具体实现,今天利用仅有的一点语言知识勉强弄懂了具体实现的步骤。于是写文章来梳理思路。
原理:对于一个乱序的数组,我们可以任取其中一个元素(为了递归方便,通常取数组或小块数组的第一个数),将小于它的放在左边,将大于它的放在右边,然后再分成的两个小块数组中重复进行此操作,递归至小块数组只剩一个元素,则排序完成。
具体实现:
假设有一个乱序数组
int[] a={7,2,5,4,8,6}
我们取出第一个元素:
int v=a[0];
然后呢,我们设置两个指针l(left)和r(right),分别指向数组的左端和右端。
int left=0;int right=a.length-1;
这是一个递归的算法,我们的函数头部应为:
public int[] quickSort(int[] a,int left,int right);

我们已经取出了a[0]的值。
我们从右端right处开始比较,若a[right]<v,则把它放到v的左边去,具体实现就是使6放到7处去,然后再把7放到6原来的位置上去,就是交换元素,这样就实现了小数放在v的左边的操作。当元素符合条件时,只要指针向中间靠拢,继续比较即可。
//由于要递归操作,我们用int i=left;int j=right;来取出传递进函数的两个指针值。
//我们要不断地从左右两边查找,所以外层会有一个大循环,下面是从右边开始查找的代码的一部分。
while(i<j&&v<a[j]){
j--;
}//元素符合要求,则继续向中间靠拢。
a[i]=a[j];
a[j]=v;//两行代码交换元素

右边指针处成了“空处”,我们再从左边指针处开始比较。
a[left]<v,符合,继续向两指针中间靠拢,直到8为止;

8>7,他应该在v=7的右边,不符合,我们将它与取出来的元素交换位置。

我们交换了位置,然后再次从右边指针处开始查找。
与右边查找相应,左边代码为:
while(i<j&&a[i]<v){
i++;
}//推进
a[j]=a[i];
a[i]=v;//交换
右边继续推进,我们发现两指针重合了,第一次查找和分块放置结束。

这是我们进行一次二分的代码。
int v=a[left];
int i=left;
int j=right;
while(i<j)
{
while(i<j&&v<a[j])
{ j--; } a[i]=a[j]; a[j]=v;
while(i<j&&v>a[i])
{ i++; } a[j]=a[i]; a[i]=v;
}
我们想要将它完全排序,我们需要进一步将它分成的两个小块来进行二分,小的放左边,大的放右边,直到我们二分的小块数组只剩下一个元素,则不用继续二分排序。这时,我们继续进行二分,就会造成左指针比右指针大的情况。
那么我们的递归结束条件应该是:
if(left>=right){
return a;
}
我们的递归主体应该在上述进行一次排序的后面加上:
this.quickSort(a,i+1,right);
this.quickSort(a,left,j-1);//i与j相等,无论怎么用,a[i]处的元素我们已经确定好了他的位置,不用再管,只用排它两侧的。
那么我们就完成了一个快速排序算法。
附完整java代码如下:
class Solution
{
public int[] quickSort(int[] a,int left,int right) {
if(left>=right) { return a; }
int v=a[left];
int i=left;
int j=right;
while(i<j){
while(i<j&&v<a[j])
{ j--; }
a[i]=a[j]; a[j]=v;
while(i<j&&v>a[i])
{ i++; }
a[j]=a[i]; a[i]=v;
}
this.quickSort(a,i+1,right);
this.quickSort(a,left,j-1);
return a;
}
}
欢迎友善讨论,如有错处望请指正。