十大排序算法快速排序之Java实现

快速排序

快速排序(Quick Sort)是对冒泡排序的一种改进,采用的是分治策略(一般与递归结合使用),以减少排序过程中的比较次数。

快速排序在1960年由查尔斯·安东尼·理查德·霍尔(Charles Antony Richard Hoare,缩写为C. A. R. Hoare)提出,昵称为东尼·霍尔(Tony Hoare)。

算法步骤

  1. 从数组中选择一个轴点元素(pivot),假设每次都选择索引为0的元素为轴点元素。
  2. 利用pivot将数组分割成2个子数组,将小于pivot的元素放在pivot前面(左侧),将大于pivot的元素放在pivot后面(右侧),等于pivot的元素放哪边都可以。
  3. 递归对子序列进行前面两步操作,直到不能再分割(子序列中只剩下1个元素)。

快速排序的本质:逐渐将每一个元素都转换成轴点元素。

在这里插入图片描述

动图演示

在这里插入图片描述

代码实现

package com.morris.data.struct.sort.cmp;

import com.morris.data.struct.sort.AbstractSort;

/**
 * 快速排序
 */
public class QuickSort<E extends Comparable> extends AbstractSort<E> {

    @Override
    protected void sort() {
        sort(0, array.length);
    }

    private void sort(int begin, int end) {

        if(end - begin < 2) {
            return;
        }

        int pivotIndex = pivotIndex(begin, end);

        sort(begin, pivotIndex);
        sort(pivotIndex + 1, end);

    }

    /**
     * 返回轴点元素的真正索引
     * @param begin
     * @param end
     * @return
     */
    private int pivotIndex(int begin, int end) {

        // 随机选择一个元素跟begin位置进行交换,为了降低最好时间复杂度
        swap(begin, begin + (int)(Math.random() * (end - begin)));

        E pivot = array[begin];
        end--;

        while (begin < end) {

            while (begin < end) {
                // 从右向左扫描
                if(cmp(array[end], pivot) < 0) {
                    array[begin++] = array[end];
                    break;
                } else {
                    end--;
                }
            }

            while (begin < end) {
                // 从左向右扫描
                if(cmp(array[begin], pivot) > 0) {
                    array[end--] = array[begin];
                    break;
                } else {
                    begin++;
                }
            }
        }

        array[begin] = pivot; // begin==end

        return begin;
    }
}

在轴点左右元素数量比较均匀的情况下,同时也是最好的情况,所以最好时间复杂度和平均时间复杂度均为O(nlogn)。

如果轴点左右元素数量极度不均匀就会出现最坏情况,所以最坏时间复杂度为O(n^2)。

为了降低最坏情况的出现概率,一般采取的做法是:随机选择轴点元素。

由于递归调用的缘故,所以空间复杂度为O(logn)。

对相等元素的处理

当代码中下面两处的比较为<或>时,快速排序对相等元素的处理过程如下:

...
// 从右向左扫描
if(cmp(array[end], pivot) < 0) {
...
...
// 从左向右扫描
if(cmp(array[begin], pivot) > 0) {
...

在这里插入图片描述

如果数组中的所有元素都与轴点元素相等,利用目前的算法实现,轴点元素可以将数组分割成2个均匀的子序列。

当代码中下面两处的比较为<=或>=时,快速排序对相等元素的处理过程如下:

...
// 从右向左扫描
if(cmp(array[end], pivot) <= 0) {
...
...
// 从左向右扫描
if(cmp(array[begin], pivot) >= 0) {
...

在这里插入图片描述
根据轴点元素分割出来的子数组极度不均匀,会导致出现最坏时间复杂度O(n^2)。

更多精彩内容关注本人公众号:架构师升级之路
在这里插入图片描述

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

morris131

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值