快排算法的针对重复键值的优化

  上一节讲了快排算法在序列基本有序的情况下的两种优化方法,这一节我们对新的测试用例进行测试,测试用例如下所示:

int main()
{
    //测试 - 待排序列的重复值很多
    int n = 400000;
    int *arr = SortTestHelper::generateRandomArray(n, 0, 10);
    int *arr2 = SortTestHelper::copyIntArray(arr, n);
    SortTestHelper::testSort("mergeSort", mergeSort, arr, n);
    SortTestHelper::testSort("qucikSort2", quickSort, arr2, n);
    delete[] arr;
    delete[] arr2;
    return 0;
}
测试结果如下:



  可见,对于数据量很大,并且重复数据很多的情况,即使是上一节优化过的快排算法,其时间性能也是不能接受的,这里针对这种重复数据量大的情况对快排算法作出进一步优化。

  首先,先看__patition()函数的操作:

template<typename T>
int __patition(T arr[], int l, int r)
{
    //在arr[l...r]中随机选取一个元素作为标定点,并将其和序列第一个元素交换
    swap(arr[l], arr[rand() % (r - l + 1) + l]);
    T v = arr[l];

    int j = l;
    for(int i = l + 1; i <= r; i++)
    {
        if(arr[i] < v)
        {
            swap(arr[j + 1], arr[i]);
            j++;
        }
    }
    swap(arr[l], arr[j]);
    return j;
}
  在 if 语句中,是将<v的元素放在橙色部分,而>=v的元素全部放置在紫色部分。


  当序列中存在大量重复元素(即大量等于v的元素时),最后就会出现极度不平衡的现象,如下:


  那么这样得到的快排递归树也是很不平衡的,树的深度就会超过logn,总的时间复杂度就会大于O(nlogn)很多,甚至退化成O(n^2)的时间复杂度。

  于是,对快排算法我们采取另一种思想:即不是将<v和>v的部分都放在序列的一头,而是分别放在序列的左右两头,如下所示:

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值