这就是一道简单的数组排序问题,借这道题回顾和复习一下快速排序算法的实现。
快速排序被普遍认为是当下速度最快的排序算法之一,在处理大规模数据时其性能表现一般很好。然而,快速排序算法是输入敏感的(Input-Sensitive)算法,也就是其实际执行的耗时和输入序列的情况密切相关,也和我们找到的划分点Pivot在序列中排序之后的实际位置有关。
快速排序算法的思想很简单,也就是在待排序序列中按一定策略找出一个划分点元素Pivot,将比Pivot小的元素排列在Pivot左边,比Pivot大的元素排在Pivot右边。再在左右两个子序列递归执行此算法(典型的减而治之算法策略),当退化到子序列长度为1时退出,这时整个序列全部有序。
如果每次我们都能确保取到的Pivot处于序列中的接近中间的大小位置,那么算法的性能能达到最优,可惜在无序序列中很难做到这一点。但是注意,Pivot的选择策略在某种程度上决定了这个算法的性能,常见的取Pivot的形式有:
// 1.直接取第一个元素作为Pivot
int Pivot = seq[0];
// 2.取序列中心元素为Pivot
int Pivot = seq[seq.size() / 2];
// 3.随机生成一个有效范围内的索引值,这样在统计意义上保证性能不会太差,有效索引区间是[Begin, End]
// 但是这样做每次算法的表现都会是一个不确定的情况,可能很好,可能不太好
int RandomIndex = (1.0 * rand() / RAND_MAX) * (End - Begin + 1) + Begin;
int Pivot = seq[RandomIndex];
下面是对算法的一个具体实现,首先是按照一定策略取Pivot并按此Pivot划分序列:
int getPivot(vector<int>& nums, int Begin, int End)
{
// generate a random index in intervel [Begin, End]
/*3 different strategies*/
int RandomIndex = (1.0 * rand() / RAND_MAX) * (End - Begin + 1) + Begin;
// int RandomIndex = (Begin + End) / 2;
// int RandomIndex = 0;
// storing the temporary variable
int Pivot = nums[RandomIndex];
// swap the Pivot with nums[Begin], so we need to start from End to fill the Begin
swap(nums[Begin], nums[RandomIndex]);
// loop until Begin == End
while(Begin < End)
{
// find the first element which is < Pivot
while(Begin < End && nums[End] >= Pivot)
--End;
nums[Begin] = nums[End];
// symmetrical to above situation
while(Begin < End && nums[Begin] < Pivot)
++Begin;
nums[End] = nums[Begin];
}
// assert (Begin == End);
// put the Pivot in nums[Begin](nums[End])
nums[Begin] = Pivot;
return Begin;
}
注意上面的代码中,如果我们选取的Pivot不是nums[0],我们就将它和nums[Begin]做一个交换,这样是为了保证我们的序列遍历从两端开始进行。也正因为此,我们的第一个while循环:
// find the first element which is < Pivot
while(Begin < End && nums[End] >= Pivot)
--End;
nums[Begin] = nums[End];
从序列的尾部开始向开头搜索(因为这时候nums[Begin]存储的就是Pivot,而Pivot已经被记录到变量Pivot中,所以此位置可覆盖)。这个函数实现了Pivot的选取和基于Pivot的序列划分,返回值是Pivot最终插入的位置。
然后,我们递归的对左右两侧进行同样的操作,注意递归基(我取的是闭区间[Begin, End]):
void quickSort(vector<int>& nums, int Begin, int End)
{
if(Begin >= End)
return;
// get the Pivot of nums
int Pivot = getPivot(nums, Begin, End);
// sort the Begin & End subsequence recursively
quickSort(nums, Begin, Pivot - 1);
quickSort(nums, Pivot + 1, End);
}
这就是完整的快速排序QuickSort算法,最终在主函数中调用之即可:
vector<int> sortArray(vector<int>& nums) {
// generate a random seed
srand((int)time(NULL));
quickSort(nums, 0, nums.size() - 1);
return nums;
}