排序算法-快速排序的时间复杂度分析

快速排序的思想是在数组[p,r]中选择一个分区点q,将数组一分为2,同时将小于分区点的数值的放到分区点左侧[p,q-1],大于分区点的数值的放到分区点右侧[q+1,r],重复这个过程。

快速排序也是用到了分治思想和递归实现方式,这一点跟归并排序是一样的,但是快速排序的实现跟归并是完全不一样的。

归并排序是先分解再合并,从下到上解决问题。

快速排序是从上到下进行分区实现排序。俯视这个过程像是层次不同的拼图一般,完整组合成有序序列。

/**
     * 快速排序
     * @param arr
     * @param n
     */
    public static void quickSort(int[] arr,int n){

        quickSort(arr,0,n-1);

    }

    /**
     * 根据分区点,递归继续分解子分区
     * @param arr
     * @param p
     * @param r
     */
    public static void quickSort(int[] arr,int p,int r){
        if(p>=r){
            return;
        }
        int q = partition(arr,p,r);
        quickSort(arr,p,q-1);
        quickSort(arr,q+1, r);
    }

    /**
     * 快排分区
     *随机生成[p,r]区间内pivot,将比pivot大的放在其右侧,比pivot小的放在其左侧
     * @param arr
     * @param p
     * @param r
     */
    public static int partition(int[] arr,int p,int r){
        int pivot = arr[r];
        int i=p;
        for (int j = p; j < r; j++) {
            //当前元素比分区点小,则交换当前元素arr[j]到arr[i],也就是将小的移动到左侧,大的移动到右侧,而这个大小也是相对于分区点来说的,将来分区点会放到中间位置
            if(arr[j] < pivot){
                int temp = arr[j];
                arr[j] = arr[i];
                arr[i] = temp;
                //交换完位置(每确定完一个小元素后)以后,移动i指针到下一位(这个位置也是为下一个小元素准备的),只要arr[j]比分区点小,就将其交换到指针i的位置,并将i后移
                i++;
            }
        }
        //迭代完成后,所有相对于pivot小的元素都被移动到靠左的位置(i指针动态指向的位置),所有相对于pivot大的元素都被移动到右侧,但是还是需要pivot将大小区间分割开
        int temp = arr[i];
        arr[i]=arr[r];
        arr[r]=temp;
        return i;
    }

用一张图片解读下代码,这里描述的分区过程,将大于pivot的放在左边,将小于pivot的放在右边:

 

快速排序是原地排序算法吗?

快速排序是原地排序算法,不需要额外存储空间。内部元素交换完成排序。

快速排序是稳定排序算法吗?

6,8,7,6,3,5,9,4,在经过第一次分区操作之后,两个6的顺序会变,所以快速排序不是稳定排序算法。

快速排序算法的时间复杂度是多少?

因为快速排序跟归并排序一样都是采用的分治思想使用递归实现,所以归并排序的时间复杂度计算公式也一样适用,前提是每次快速排序选择的pivot都可以将数组正好一分为二。

T(1) = C;   n=1 时,只需要常量级的执行时间,所以表示为 C。
T(n) = 2*T(n/2) + n; n>1
 

但是,这种情况很难实现。极端情况下一个数组已经是有序,如果pivot每次都选择数组最后一个,那每次分区得到的两个子区间都是不均等的。大约需要n次分区才能完成整个快排。所以这种非常坏的情况下时间复杂度就从极好情况下的O(nlogn)退化成O(n^2).那么平均时间复杂度呢?这里可以说大部分情况下可以做到O(nlogn),极端情况下才会退化O(n^2),但是这个是可以用很多办法去避免的。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

jeff.sheng

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

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

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

打赏作者

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

抵扣说明:

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

余额充值