快速排序对于有序数组导致的栈溢出的优化

https://blog.csdn.net/u013025748/article/details/116590656

由于归并排序空间复杂度问题,快速排序比较适合来实现排序函数,但是,我们也知道,快速排序在最坏情况下也就是数组有序的时候的时间复杂度是 O(n2),如何来解决这个“复杂度恶化”的问题呢?

目录

一、如何优化快速排序?选择合适分区点:

1. 三数取中法

2. 随机法

二、警惕堆栈溢出:

1、限制递归深度:

2、在堆上模拟实现一个函数调用栈:


一、如何优化快速排序?选择合适分区点:

O(n2) 时间复杂度出现的主要原因还是因为我们分区点选得不够合理。最理想的分区点是:被分区点分开的两个分区中,数据的数量差不多。最坏的情况就是每次都没有有效分区,导致所有数据都在一个区中。

因此想要优化快速排序算法,就需要选择合适的分区点:

1. 三数取中法

我们从区间的首、尾、中间,分别取出一个数,然后对比大小,取这 3 个数的中间值作为分区点。这样每间隔某个固定的长度,取数据出来比较,将中间值作为分区点的分区算法,肯定要比单纯取某一个数据更好。

但是,如果要排序的数组比较大,那“三数取中”可能就不够了,可能要“五数取中”或者“十数取中”。

2. 随机法

随机法就是每次从要排序的区间中,随机选择一个元素作为分区点。

这种方法并不能保证每次分区点都选的比较好,但是从概率的角度来看,也不大可能会出现每次分区点都选得很差的情况,所以平均情况下,这样选的分区点是比较好的。时间复杂度退化为最糟糕的 O(n2) 的情况,出现的可能性不大。

二、警惕堆栈溢出:

快速排序是用递归来实现的,递归要警惕堆栈溢出。为了避免快速排序里,递归过深而堆栈过小,导致堆栈溢出,有两种解决办法:

1、限制递归深度:

一旦递归过深,超过了我们事先设定的阈值,就停止递归。

2、在堆上模拟实现一个函数调用栈:

手动模拟递归压栈、出栈的过程,这样就没有了系统栈大小的限制。

三、示例:

比如如下示例,出现了栈溢出错误,原因是当原数列是有序时,递归次数太多。

现改用优化代码思路:

    void qsort(int l, int r) {
        int tmp = a[(l+r)/2], i = l, j = r;
        while(i <= j) {
            while(a[j]>tmp) j--;
            while(a[i]<tmp) i++;
            if(i<=j) {
                int t = a[i]; a[i] = a[j]; a[j] = t;
                i++;
                j--;
            }
        }
        if(i<r) qsort(i, r);
        if(j>l) qsort(l, j);
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值