//划分排序
public int partionIt(int low,int upper)//数组上界与下界
{
int left=low;//left为左指针
int right=upper;//right为右指针
int pivot=a[upper];//pivot为中心点
while(true)
{
while(a[left]<pivot) //注意不能等于,图像说明情况
left++; //若左指针所指向的数组元素小于中心点,则左指针右移
while(a[right]>pivot)//注意不能等于,图像说明情况
right--; //若右指针所指向的数组元素大于中心点,则右指针左移
if(left==right) //代表遍历结束,即时间复杂度为O(upper-low)
return left; //也可以写return right
if(a[left]==a[right])//防止两个数永无止境的交换
left++; //也可以right++
else
{
int temp=a[left]; //交换
a[left]=a[right];
a[right]=temp;
}
}
}
此时left指向5,right指向9,pivot为9。left当指向12时由于比9大于则left锁定12。我们注意到刚才强调的不能等于,则right一开始就锁定了9,即12与9互换位置,如下图所示:
由于9等于pivot,所以left锁定了9,而right当从12右边遍历到9等于pivot则锁定了9。我们应该注意到一个问题由于pivot为9,a[left]<pivot,a[right]>pivot的原因,所以总会有一个指针指向9,即left没有遍历就锁定了9,而right当指向9由于不符合a[right]>pivot的条件跳出whlie循环锁定了9。如下图所示:
如果我们删去这两行代码
则会导致交换完之后left,right又再次锁定各自的9,又交换,不断循环下去不断交换。注意我们前言提到:
所以此时我们让left++或者right++则跳出死循环,如图所示:
则出现如下情况:
此时 left和right相等,且以划分好数组,即left与right都指向了9,9也为pivot中心点。,我们返回pivot。
注意左遍历右遍历到同一个点,不会出现left>=right,只会出现left和right相等,也符合我们的逻辑思维,左遍历与右遍历到一个点,即遍历一次!时间复杂度为0(n)。
则我们代码为:
接着我们基于划分排序,利用递归实现快速排序。
public void quickSort(int low,int upper)
{
//我们在划分左半数组和右半数组时,可能出现数组只有一个数,或者数组压根就没有数了,所以是low>=upper
if(low >= upper)
{
return;
}
int pivotIdx = partionIt(low, upper);//pivotIdx所得到的值即我们前言所说的中点值
// 我们将中点值往左划分为左半数组quickSort
quickSort(low, pivotIdx - 1);
// 我们将中点值往右划分为右半数组quickSort
quickSort(pivotIdx+1, upper);
}
如图所示给一个数组
则最终为:
即划分排序中返回left,此时我们获取到了pivot的下标。
根据这几行代码。
将数组划分为左右,我们不考虑将pivot的值划分到左数组或者右数组,这符合逻辑思维,也可以让划分排序少一个数。如图所示
我们先分析左数组,左数组中只有一个元素则return。
再分析右数组,如图所示:
最终结果为:
我们注意到中点值划分左右,右数组是没数的
// 我们将中点值往右划分为右半数组quickSort
quickSort(pivotIdx+1, upper);
注意pivotdx+1比upper大一个值
所以我们在实现代码时候是
if(low >= upper)
{
return;
}
不能只写low==upper,否则会导致运行错误。应该得包含low>upper
最后数组结果为: