背景
目录
解决单路快速排序所存在的问题,即:在基准值存在大量重复值时,(>=v)部分和(<v)部分分配及其不均衡,算法会退步称为 0(n2) 级别的算法。
为了解决这个问题,衍生出双路快速排序:
思路
其他部分和普通快速排序相同,主要更改主过程Partition部分。
从数组中随机选择一点将其作为基准点,并与数组第一个元素交换位置,称其为V点。
在数组中设置4个索引:
l:数组最左侧元素
r:数组最右侧元素
i:比较当前元素是否<v,起始点为(l+1)
j:比较当前元素是否>v,起始点为r
Partition开始
i点比较当前元素是否<V,若小于V,向后移动一位,i++;若>=V,循环停止。(附加停止条件:整个数组遍历完毕,i=r)
j点比较当前元素是否>V,若大于V,向前移动一位,j--;若<=V,循环停止。(附加停止条件:整个数组遍历完毕,j=l+1)
两循环停止后,将索引 i, j 所指向的元素交换位置。
中间部分继续重复进行以上操作,直到 i,j 重合,l与 i/j 交换,此次Partiton结束。
Partition代码实现
int _Partition_2(T arr[] , int l , int r){
//初始化:从数组中随机选择一点将其作为基准点,并与数组第一个元素交换位置,称其为V点。
T x = (l + rand()%(r-l+1));
swap(arr[l],arr[x]);
T v = arr[l];
cout<<endl;
int i = l+1;
int j = r;
//将arr[l]后的元素排序,i前为<v,i后为>v,排序后交换arr[l]和arr[i],返回i
while (true) {
//i点比较当前元素是否<V,若小于V,向后移动一位,i++;若>=V,循环停止。(附加停止条件:整个数组遍历完毕,i=r)
while (arr[i] < v && i <= r) {i++;}
//j点比较当前元素是否>V,若大于V,向前移动一位,j--;若<=V,循环停止。(附加停止条件:整个数组遍历完毕,j=l+1
while (arr[j] > v && j >= l+1) { j--; }
if(i>j){break;}
swap(arr[i], arr[j]);
i++;
j--;
}
swap(arr[l],arr[j]);
return j;
}
完整实现
#include <iostream>
#include <algorithm>
#include "../SortTestHelper.h"
using namespace std;
template <typename T>
int _Partition_2(T arr[] , int l , int r){
//初始化:从数组中随机选择一点将其作为基准点,并与数组第一个元素交换位置,称其为V点。
T x = (l + rand()%(r-l+1));
swap(arr[l],arr[x]);
T v = arr[l];
int i = l+1;
int j = r;
//将arr[l]后的元素排序,i前为<v,i后为>v,排序后交换arr[l]和arr[i],返回i
while (true) {
//i点比较当前元素是否<V,若小于V,向后移动一位,i++;若>=V,循环停止。(附加停止条件:整个数组遍历完毕,i=r)
while (arr[i] < v && i <= r) {i++;}
//j点比较当前元素是否>V,若大于V,向前移动一位,j--;若<=V,循环停止。(附加停止条件:整个数组遍历完毕,j=l+1
while (arr[j] > v && j >= l+1) { j--; }
if(i>j){break;}
swap(arr[i], arr[j]);
i++;
j--;
}
swap(arr[l],arr[j]);
return j;
}
template <typename T>
void _quickSort2(T arr[] ,int l ,int r){
if(l>=r){return;}
else{
int p = _Partition_2(arr,l,r);
_quickSort2(arr,l,p);
_quickSort2(arr,p+1,r);
}
}
template <typename T>
void quickSort2(T arr[] , int n){
srand((int)(time((NULL))));
_quickSort2(arr,0,n-1);
}
int main(){
//测试
int *arr = SortTestHelper::generateRandomArray(10,0,10);
for(int i = 0;i<10;i++){
cout<<arr[i];
}
cout<<endl;
quickSort2(arr,10);
for(int i = 0;i<10;i++){
cout<<arr[i];
}
cout<<endl;
return 0;
}
附
随机数产生:
srand():用于随机种子的产生,常用语法 ->srand((int)(time(NULL))),time使用前需要先导入<ctime>
产生一定范围随机数的通用表示公式 -> a + rand() % n
a: 随机数起始位置
n: 整数的范围
#include<iostream>
#include<ctime>
int main() {
srand((int)time(NULL));
int a = 5;
int b = 10;
//[a,b] (a+rand()%(b-a+1)) ;
//(a,b] (a+1 + rand()%(b-a));
//[a,b) (a + rand()%(b-a));
//(a,b) (a+1 + rand()%(b-a-1));
for (int i =0 ; i<50; i++){
cout<<(a+1 + rand()%(b-a-1))<<"-";
}
}