两路快排,跳出while时,得到[0,i)是<=base的数,(i,length)是>=base的数
public void quickSort(int left,int right,int[] nums){
//在[left.right]中进行排序
//如果左边索引比右边索引大,是不合法的,直接结束
if(left>right)
return;
int base=nums[left];
int i=left;
int j=right;
//i和j不相遇时,在循环中进行检索
while(i!=j){
//先由j从右往左检索比基准数小的,检索到就停下
//如果检索到比基准数大或相等的,继续检索
//i<j保证检索不越界
while(nums[j]>=base&&i<j)
j--;
while(nums[i]<=base&&i<j)
i++;
//如果代码走到这里,i停下了,j停下了,然后交换i和j位置的元素
int temp=nums[j];
nums[j]=nums[i];
nums[i]=temp;
}
//i=j,i和j相遇,停止检索,将基准数和相遇位置元素交换
nums[left]=nums[j];
nums[j]=base;
//此时,基准数左边的元素都比它小,右边的元素都比它大
quickSort(left,i-1,nums);
quickSort(i+1,right,nums);
}
三路快排
选取一个标定点,由于有很多个和标定点相等的元素,将整个数组分成三份,之后对v的部分进行递归的三路快排,可以跳过很多对与标定点相等元素的考察;如果数组中所有元素都相等,经过第一轮的三路快排就完成了对数组的所有操作,进化成了一个O(n)的算法;对近乎有序或无序的数组效果好
i是当前遍历到的元素 e==v i++
i<v 当前元素和等于v的第一个元素交换位置,融入<v的部分, lt++ i++
lt>v 当前元素和>v部分的前一个元素交换位置,融入>v的部分,gt–,此时索引i不应该++,因为该位置是一个还没有考察的元素,需要继续考察
终止条件gt==i,当前没有任何元素需要考察
最后需要将lt的元素和l的元素交换位置,lt是标定点最终所在的位置,和==v的部分融为一体
下一步对<v和>v的部分进行排序
public void quickSort3Way(int left,int right,int[] nums){
if(left>=right)
return;
int base=nums[left];
//<v部分无元素[left+1,left]
int lt=left;
//>v部分无元素[right+1,right]
int gt=right+1;
//在[left+1,right]间搜索
int i=left+1;
int temp=0;
while(i!=gt){
if(nums[i]<base){
temp=nums[i];
nums[i]=nums[lt+1];
nums[lt+1]=temp;
lt++;
i++;
}
else if(nums[i]==base)
i++;
else {
temp=nums[gt-1];
nums[gt-1]=nums[i];
nums[i]=temp;
gt--;
}
}
temp=nums[lt];
nums[lt]=nums[left];
nums[left]=temp;
quickSort3Way(left,lt-1,nums);
quickSort3Way(gt,right,nums);
}