我们知道快排的核心思想是选取一个基准值,通常我们总是选取最左边的元素作为基准值,并以这个基准值来将数组划为两部分,左边部分为小于基准值,右边部分为小于基准值。
但往往我们的数组并不是那么理想的乱序如
- 数组为基本有序的,只有少数元素是有序的
- 此时我们选取最左边的元素作为基准值就可能照成数组的两部分极度不平衡
- 解决办法
- 每次选取基准值时选取一个·随机值
- 数组存在大量的重复元素
- 此时使用也可能照成数组的两部分极度不平衡
- 单路快排
//单路快排
void quickSort(vector<int> &arr,int l,int r)
{
if(arr.size() <= 1)
return ;
if(l >= r)
return ;
//避免有序情况下两边极度不平衡
swap(arr[l],arr[rand()%(r-l+1)]);
int j = l;
int v = arr[l];
for(int i = l+1;i <= r;i++)
{
if(arr[i] < v)
{
j ++;
swap(arr[j],arr[i]);
}
}
swap(arr[l],arr[j]);
quickSort(arr,l,j-1);
quickSort(arr,j+1,r);
- 双路快排
//双路快排
void quickSort2(vector<int> &arr,int l,int r)
{
if(arr.size() <= 1)
return ;
if(l >= r)
return ;
swap(arr[l],arr[rand()%(r-l+1)]);
int i = l+1;
int j = r;
while(true)
{
while(i <= r && arr[i] < v)
i++;
while(j >= l+1 && arr[j] > v)
j--;
if(i > j)
break;
swap(arr[i++],arr[j--]);
}
swap(arr[l],arr[j]);
quickSort2(arr,l,j-1);
quickSort2(arr,j+1,r);
}
- 三路快排
//三路快排
void quickSort3(vector<int> &arr,int l,int r)
{
if(arr.size() <= 1)
return ;
if(l >= r)
return ;
swap(arr[l],arr[rand()%(r-l+1)]);
int lt = l;
int gt = r+1;
int v = arr[l];
int i = l+1;
while(i < gt)
{
if(arr[i] < v)
{
swap(arr[++lt],arr[i++]);
}
else if(arr[i] > v)
{
swap(arr[--gt],arr[i]);
}
else
i++;
}
swap(arr[l],arr[lt]);
quickSort3(arr,l,lt-1);
quickSort3(arr,gt,r);
}
一般来说我们的双路快排就能解决上述问题,我们标准库体供的sort()一般使用三路快排。