您当前的位置: 首页 >  算法

顧棟

暂无认证

  • 0浏览

    0关注

    227博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

【重温基础算法】内部排序之快速排序法

顧棟 发布时间:2022-09-15 22:51:51 ,浏览量:0

内部排序之快速排序法

文章目录
  • 内部排序之快速排序法
    • 主要思想
    • 过程演示
    • JAVA代码
    • 算法分析
      • 时间复杂度分析
        • 最好时间复杂度
        • 最坏时间复杂度
        • 平均时间复杂度
      • 空间复杂度
对冒泡排序的一种优化

主要思想

快速排序是C.R.A.Hoare于1962年提出的一种划分交换排序。它采用了一种分治的策略,通常称其为分治法(Divide-and-ConquerMethod)。

通过一趟排序将待排记录分割成独立的两个部分,一部分的关键字比另一部分的关键字小,则可以分别对两部分记录继续进行排序。

  1. 选取任务选取的一个记录,作为枢轴或(支点)(pivot)
  2. 重新排列记录,所有关键字比pivot值小的摆放在pivot前面,所有关键字比pivot值大的摆在pivot的后面(相同的数可以到任一边)。在这个分区退出之后,该pivot就处于数列的中间位置。这个称为分区(partition)操作;
  3. 重复执行步骤2。把小于pivot关键字的子数列和大于pivot关键字的子数列排序。
过程演示

在这里插入图片描述

JAVA代码
package sort;

public class QuickSort {

    private static int count = 1;

    public static void main(String[] args) {
        int[] o = {49, 38, 45, 27, 46, 13, 27, 8};
        System.out.print("排序前: ");
        for (int t : o) {
            System.out.print(t);
            System.out.print(" ");
        }
        System.out.println();

        // 算法部分
        int left = 0;
        int right = o.length - 1;

        quickSort(o, left, right);

        System.out.print("排序后: ");
        for (int t : o) {
            System.out.print(t);
            System.out.print(" ");
        }
        System.out.println();

    }

    private static void quickSort(int[] arr, int left, int right) {
        if (left 1​ 其中  
     
      
       
       
         D 
        
       
         ( 
        
       
         n 
        
       
         ) 
        
       
         = 
        
       
         n 
        
       
         − 
        
       
         1 
        
       
      
        D(n)=n−1 
       
      
    D(n)=n−1 ,是一趟快排需要的比较次数,一趟快排结束后将数组分成两部分 
     
      
       
        
        
          I 
         
        
          1 
         
        
       
      
        I_1 
       
      
    I1​ 和 
     
      
       
        
        
          I 
         
        
          2 
         
        
       
      
        I_2 
       
      
    I2​。

最好时间复杂度

最好的情况是,每一次划分都正好将数组分成长度相等的两半 T ( n ) = { D ( 1 ) n ≤ 1 D ( n ) + T ( n 2 ) + T ( n 2 ) n > 1 T(n)= \begin{cases} D(1) & {n \leq 1} \\ D(n)+T(\frac{n}{2})+T(\frac{n}{2}) &{n >1 } \end{cases} T(n)={D(1)D(n)+T(2n​)+T(2n​)​n≤1n>1​

∴ T ( n ) = D ( n ) + 2 T ( n 2 ) = D ( n ) + 2 D ( n 2 ) + 2 T ( n 4 ) . . . = D ( n ) + 2 D ( n 2 ) + 4 D ( n 4 ) + . . . + 2 k D ( n 2 k ) = n − 1 + 2 ( n 2 − 1 ) + 4 ( n 4 − 1 ) + . . . + 2 k ( n 2 k − 1 ) = ( n − 1 ) + ( n − 2 ) + ( n − 4 ) + . . . + ( n − 2 k )    ⟹    ∑ k = 1 n n − 2 k = k n − 2 k + 1 ∵ k = l o g 2 n ∴ 原式 = n l o g 2 n − 2 n + 1    ⟹    O ( n l o g 2 n ) \begin{aligned} \therefore T(n)&=D(n)+2T(\frac{n}{2}) \\ &=D(n)+2D(\frac{n}{2})+2T(\frac{n}{4}) \\ &.\\ &.\\ &.\\ &=D(n)+2D(\frac{n}{2})+4D(\frac{n}{4})+...+2^kD(\frac{n}{2^k}) \\ &=n-1+2(\frac{n}{2}-1)+4(\frac{n}{4}-1)+...+2^k(\frac{n}{2^k}-1) \\ &=(n-1)+(n-2)+(n-4)+...+(n-2^k) \\ &\implies \displaystyle \sum_{k=1}^{n} n-2^k=kn-2^k+1 \\ &\because k=log_2^n\\ &\therefore 原式=nlog_2^n-2n+1 \implies \boxed{O(nlog_2^n)}\\ \end{aligned} ∴T(n)​=D(n)+2T(2n​)=D(n)+2D(2n​)+2T(4n​)...=D(n)+2D(2n​)+4D(4n​)+...+2kD(2kn​)=n−1+2(2n​−1)+4(4n​−1)+...+2k(2kn​−1)=(n−1)+(n−2)+(n−4)+...+(n−2k)⟹k=1∑n​n−2k=kn−2k+1∵k=log2n​∴原式=nlog2n​−2n+1⟹O(nlog2n​)​​

最坏时间复杂度

最坏情况下,每一次划分都将数组分成了 0 0 0和 n − 1 n-1 n−1两部分 T ( n ) = { D ( 1 ) n ≤ 1 D ( n ) + T ( n − 1 ) + T ( 0 ) n > 1 T(n)= \begin{cases} \vcenter D(1) &{n \leq 1} \\ D(n)+T(n-1)+T(0) &{n >1 } \end{cases} T(n)={D​(1)D(n)+T(n−1)+T(0)​n≤1n>1​

∴ T ( n ) = D ( n ) + 2 T ( n − 1 ) = D ( n ) + D ( n − 1 ) + T ( n − 2 ) . . . = D ( n ) + D ( n − 1 ) + D ( n − 2 ) + . . . + D ( 1 ) = ( n − 1 ) + ( n − 2 ) + ( n − 3 ) + . . . + 0    ⟹    ∑ k = 0 n k = n ( n − 1 ) 2 原式 = n ( n − 1 ) 2    ⟹    O ( n 2 ) \begin{aligned} \therefore T(n)&=D(n)+2T(n-1) \\ &=D(n)+D(n-1)+T(n-2) \\ &.\\ &.\\ &.\\ &=D(n)+D(n-1)+D(n-2)+...+D(1) \\ &=(n-1)+(n-2)+(n-3)+...+0 \\ &\implies \displaystyle \sum_{k=0}^{n}k=\frac{n(n-1)}{2} \\ 原式&=\frac{n(n-1)}{2} \implies \boxed{O(n^2)}\\ \end{aligned} ∴T(n)原式​=D(n)+2T(n−1)=D(n)+D(n−1)+T(n−2)...=D(n)+D(n−1)+D(n−2)+...+D(1)=(n−1)+(n−2)+(n−3)+...+0⟹k=0∑n​k=2n(n−1)​=2n(n−1)​⟹O(n2)​​

平均时间复杂度

任意一种划分情况出现的概率都相等 A l l = { I 1 = 0 I 2 = n − 1 I 1 = 1 I 2 = n − 2 . . . I 1 = n − 1 I 2 = 0 All= \begin{cases} I_1=0 & I_2=n-1 \\ I_1=1 & I_2=n-2 \\ . \\ . \\ . \\ I_1=n-1 & I_2=0 \\ \end{cases} All=⎩ ⎨ ⎧​I1​=0I1​=1...I1​=n−1​I2​=n−1I2​=n−2I2​=0​

∴ T a v g ( n ) = D ( n ) + 1 n ∗ ∑ i = 0 n − 1 T a v g ( i ) + T a v g ( n − i ) = D ( n ) + 2 n ∗ ∑ i = 0 n − 1 T a v g ( i ) T a v g ( n − 1 ) = D ( n − 1 ) + 2 n − 1 ∗ ∑ i = 0 n − 2 T a v g ( i ) n T a v g ( n ) − ( n − 1 ) T a v g ( n − 1 ) = n D ( n ) + 2 ∑ i = 0 n − 1 T a v g ( i ) − ( n − 1 ) D ( n − 1 ) − 2 ∗ ∑ i = 0 n − 2 T a v g ( i ) = n D ( n ) − ( n − 1 ) D ( n − 1 ) + 2 T a v g ( n − 1 ) = n ( n − 1 ) − ( n − 1 ) ( n − 2 ) + 2 T a v g ( n − 1 ) = 2 ( n − 1 ) + 2 T a v g ( n − 1 ) 移项得 n T a v g ( n ) = 2 ( n + 1 ) + 2 T a v g ( n − 1 ) + ( n − 1 ) 2 T a v g ( n − 1 ) = 2 ( n + 1 ) + ( n + 1 ) 2 T a v g ( n − 1 ) 等式两边同时除以 n ( n + 1 ) 得 T a v g ( n ) n + 1 = T a v g ( n − 1 ) n + 2 ( n − 1 ) n ( n + 1 ) 令 B ( n ) = T a v g ( n ) n + 1 得 B ( n ) = B ( n − 1 ) + 2 ( n − 1 ) n ( n + 1 ) = B ( n − 2 ) + 2 ( n − 2 ) n ( n − 1 ) + 2 ( n − 1 ) n ( n + 1 ) . . . = B ( 1 ) + ∑ i = 1 n 2 ( i − 1 ) i ( i + 1 ) = B ( 1 ) + ∑ i = 1 n 2 ( i + 1 ) − 4 i ( i + 1 ) = ∑ i = 1 n [ 2 i − 4 i ( i + 1 ) ] ∵ ∑ i = 1 n 4 i ( i + 1 ) = 4 ∑ i = 1 n [ i + 1 − i i ( i + 1 ) ] = 4 ∑ i = 1 n [ 1 i − 1 i ( i + 1 ) ] = 4 [ 1 − 1 n + 1 ] = 4 n n + 1 ∵ ∑ i = 1 n 1 i ≈ 0.577216+ln(n) ∴ B ( n ) = 2 ∗ 0.577216 + 2 ∗ l n ( n ) + 4 n n + 1 代回 B ( n ) = T a v g ( n ) n + 1 T a v g ( n ) = 2 ( n + 1 ) l n ( n ) − 4 n + 2 ∗ 0.577216 ( n + 1 )    ⟹    O ( n l o g 2 n ) \begin{aligned} \therefore T_{avg}(n)&=D(n)+\frac{1}{n}*\displaystyle \sum_{i=0}^{n-1}T_{avg}(i)+T_{avg}(n-i) \\ &=D(n)+\frac{2}{n}*\displaystyle \sum_{i=0}^{n-1}T_{avg}(i) \\ T_{avg}(n-1)&=D(n-1)+\frac{2}{n-1}*\displaystyle \sum_{i=0}^{n-2}T_{avg}(i)\\ nT_{avg}(n)-(n-1)T_{avg}(n-1)&= nD(n)+2\displaystyle \sum_{i=0}^{n-1}T_{avg}(i)-(n-1)D(n-1)-2*\displaystyle \sum_{i=0}^{n-2}T_{avg}(i) \\ &=nD(n)-(n-1)D(n-1)+2T_{avg}(n-1) \\ &=n(n-1)-(n-1)(n-2)+2T_{avg}(n-1) \\ &=2(n-1)+2T_{avg}(n-1) \\ 移项得 \\ nT_{avg}(n) &= 2(n+1)+2T_{avg}(n-1)+(n-1)2T_{avg}(n-1) \\ &= 2(n+1)+(n+1)2T_{avg}(n-1) \\ 等式两边同时除以n(n+1)得 \\ \frac{T_{avg}(n)}{n+1}&=\frac{T_{avg}(n-1)}{n}+\frac{2(n-1)}{n(n+1)} \\ 令B(n)=\frac{T_{avg}(n)}{n+1} 得\\ B(n)&=B(n-1)+\frac{2(n-1)}{n(n+1)} \\ &=\boxed{B(n-2)+\frac{2(n-2)}{n(n-1)}}+\frac{2(n-1)}{n(n+1)} \\ .\\ .\\ .\\ &=B(1)+\displaystyle \sum_{i=1}^{n}\frac{2(i-1)}{i(i+1)} \\ &=B(1)+\displaystyle \sum_{i=1}^{n}\frac{2(i+1)-4}{i(i+1)} \\ &=\displaystyle \sum_{i=1}^{n}[\frac{2}{i}-\frac{4}{i(i+1)}] \\ \because \displaystyle \sum_{i=1}^{n}\frac{4}{i(i+1)}&= 4\displaystyle \sum_{i=1}^{n}[\frac{i+1-i}{i(i+1)}] \\ &= 4\displaystyle \sum_{i=1}^{n}[\frac{1}{i}-\frac{1}{i(i+1)}] \\ &= 4[1-\frac{1}{n+1}]=\boxed{4\frac{n}{n+1}}\\ \because \displaystyle \sum_{i=1}^{n}\frac{1}{i}&\approx \colorbox{aqua}{0.577216+ln(n)} \\ \therefore B(n)&=2*0.577216+2*ln(n)+4\frac{n}{n+1} \\ 代回B(n)=\frac{T_{avg}(n)}{n+1} \\ T_{avg}(n)&=2(n+1)ln(n)-4n+2*0.577216(n+1) \implies \boxed{O(nlog_2^n)} \\ \end{aligned} ∴Tavg​(n)Tavg​(n−1)nTavg​(n)−(n−1)Tavg​(n−1)移项得nTavg​(n)等式两边同时除以n(n+1)得n+1Tavg​(n)​令B(n)=n+1Tavg​(n)​得B(n)...∵i=1∑n​i(i+1)4​∵i=1∑n​i1​∴B(n)代回B(n)=n+1Tavg​(n)​Tavg​(n)​=D(n)+n1​∗i=0∑n−1​Tavg​(i)+Tavg​(n−i)=D(n)+n2​∗i=0∑n−1​Tavg​(i)=D(n−1)+n−12​∗i=0∑n−2​Tavg​(i)=nD(n)+2i=0∑n−1​Tavg​(i)−(n−1)D(n−1)−2∗i=0∑n−2​Tavg​(i)=nD(n)−(n−1)D(n−1)+2Tavg​(n−1)=n(n−1)−(n−1)(n−2)+2Tavg​(n−1)=2(n−1)+2Tavg​(n−1)=2(n+1)+2Tavg​(n−1)+(n−1)2Tavg​(n−1)=2(n+1)+(n+1)2Tavg​(n−1)=nTavg​(n−1)​+n(n+1)2(n−1)​=B(n−1)+n(n+1)2(n−1)​=B(n−2)+n(n−1)2(n−2)​​+n(n+1)2(n−1)​=B(1)+i=1∑n​i(i+1)2(i−1)​=B(1)+i=1∑n​i(i+1)2(i+1)−4​=i=1∑n​[i2​−i(i+1)4​]=4i=1∑n​[i(i+1)i+1−i​]=4i=1∑n​[i1​−i(i+1)1​]=4[1−n+11​]=4n+1n​​≈0.577216+ln(n)​=2∗0.577216+2∗ln(n)+4n+1n​=2(n+1)ln(n)−4n+2∗0.577216(n+1)⟹O(nlog2n​)​​

空间复杂度

快速排序的空间复杂度取决于分划基准的选择,每次都选在中间, O ( l o g 2 n ) O(log_2^n) O(log2n​)若基本有序,退化为冒泡,栈的深度 O ( n ) O(n) O(n)。

O ( l o g 2 n ) O(log_2^n) O(log2n​)就是递归的深度,递归的时候使用的栈空间稍微优化一点的快排,比如取首尾中三个数据,取其中间的值作为划分标准,不会出现退化到冒泡的可能。

计算参考:https://zhuanlan.zhihu.com/p/341201904

关注
打赏
1663402667
查看更多评论
0.2311s