快速排序

快速排序原理

从数组中任意选取一个元素,将这个元素称为中轴元素,然后我们将大于中轴元素的元素放在其右边,小于中轴元素的元素放在其左边,然后将中轴元素左边和右边分为两个小的数组,重复此过程,直到数组的大小为1,此时每个元素都处于有序的位置。

在下图的数组4,1,3,2,7,6,8中,将第一个元素设置为中轴元素,第二个元素设为i,最后一个元素设为j。然后让i和j从数组的两边向中间扫描。i向右遍历的过程中,如果遇到大于中轴元素的元素则停止移动,j向左遍历的过程中,如果遇到小于中轴元素的元素则停止移动(移动过程中需满足i <= j,不满足则停止移动)。若i和j停止移动时,i < j则交换i和j。image.png

遍历完成后将中轴元素和j指向的元素交换位置,此时中轴元素处于有序位置。image.png

对中轴元素前后两个数组重复此过程,直到数组只有一个元素image.png

代码实现

public int[] quickSort(int[] arr, int left, int right) {
        if (left < right) {
            // 获取中轴元素的下标
            int mid = partition(arr, left, right);
            // 对数组进行分割
            arr = quickSort(arr, left, mid - 1);
            arr = quickSort(arr, mid + 1, right);
        }
        return arr;
    }

    public int partition(int[] arr, int left, int right) {
        // 将第一个元素设为中轴元素
        int pivot = arr[left];
        int i = left + 1;
        int j = right;

        while (true) {
            // 向右遍历找到大于中轴元素的值
            while (i <= j && arr[i] <= pivot) i++;
            // 向左遍历找到小于中轴元素的值
            while (i <= j && arr[j] >= pivot) j--;

            if (i > j) break;

            // 元素交换
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }

        arr[left] = arr[j];
        // 将中轴元素置于有序位置
        arr[j] = pivot;

        return j;
    }

性能分析

①时间复杂度分析:最好情况,如果每次分区操作,都能正好把数组分成大小接近相等的两个小数组,那么只需要分割logn次即可,此时的时间复杂度是O(nlogn)。但是如果出现极端的情况,例如数组1,3,5,6,8,此时需要进行大约n次分区操作,才能完成快速排序。在这种情况下快速排序的时间复杂度就从O(nlogn)退化为O(n²)。而平准时间复杂度,则是假设每次中轴元素等概率着落在数组的任意位置,此时的时间复杂度是O(nlogn)。
②空间复杂度:O(logn)   ③原地排序    ④非稳定排序

中轴元素的随机选取

如果每次都以第一个元素或最后一个元素作为中轴元素,那么极端情况出现的可能性就会增加。为了降低极端情况出现的概率,我们可以随机选取中轴元素,而不是固定一个位置选取。中轴元素的随机选取有两个比较常用的分区算法。
1.三数取中法
从数组的首、尾、中间分别取出一个数,取这3个数的中间值作为中轴元素。这样取数据进行比较的分区方法,肯定比单纯取一个数要好。但是如果数组比较大,哪“三数取中”可能就不够了,就需要“五数取中”或“十数取中”。
2.随机法
随机从数组中选择一个元素作为中轴元素,这种方法不能保证每次中轴元素选的比较好,但是也不大可能出现每次都选的很差的情况,所以平均下来,退化到最糟糕的O(n²)的可能性也不大。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值