• 数据结构与算法之美10(排序)


     归并排序的原理

    如果要排序一个数组,我们先把数组从中间分成前后两部分,然后对前后两部分分别排序,再将排好序的两部分合并在一起,这样整个数组就都有序了。

    归并排序使用的就是分治思想。分治,顾名思义,就是分而治之,将一个大问题分解成小的子问题来解决。小的子问题解决了,大问题也就解决了。

    归并排序的递推公式。

    1. 递推公式:
    2. merge_sort(p…r) = merge(merge_sort(p…q), merge_sort(q+1…r))
    3. 终止条件:
    4. p >= r 不用再继续分解

     

    归并排序代码

    1. // 归并排序算法, A是数组,n表示数组大小
    2. merge_sort(A, n) {
    3. merge_sort_c(A, 0, n-1)
    4. }
    5. // 递归调用函数
    6. merge_sort_c(A, p, r) {
    7. // 递归终止条件
    8. if p >= r then return
    9. // 取p到r之间的中间位置q
    10. q = (p+r) / 2
    11. // 分治递归
    12. merge_sort_c(A, p, q)
    13. merge_sort_c(A, q+1, r)
    14. // 将A[p...q]和A[q+1...r]合并为A[p...r]
    15. merge(A[p...r], A[p...q], A[q+1...r])
    16. }

    我们把merge()函数写成伪代码

    1. merge(A[p...r], A[p...q], A[q+1...r]) {
    2. var i := p,j := q+1,k := 0 // 初始化变量i, j, k
    3. var tmp := new array[0...r-p] // 申请一个大小跟A[p...r]一样的临时数组
    4. while i<=q AND j<=r do {
    5. if A[i] <= A[j] {
    6. tmp[k++] = A[i++] // i++等于i:=i+1
    7. } else {
    8. tmp[k++] = A[j++]
    9. }
    10. }
    11. // 判断哪个子数组中有剩余的数据
    12. var start := i,end := q
    13. if j<=r then start := j, end:=r
    14. // 将剩余的数据拷贝到临时数组tmp
    15. while start <= end do {
    16. tmp[k++] = A[start++]
    17. }
    18. // 将tmp中的数组拷贝回A[p...r]
    19. for i:=0 to r-p do {
    20. A[p+i] = tmp[i]
    21. }
    22. }

    归并排序是一个稳定的排序算法

    归并排序的时间复杂度的计算公式就是:

    1. T(1) = C; n=1时,只需要常量级的执行时间,所以表示为C。
    2. T(n) = 2*T(n/2) + n; n>1
    1. T(n) = 2*T(n/2) + n
    2. = 2*(2*T(n/4) + n/2) + n = 4*T(n/4) + 2*n
    3. = 4*(2*T(n/8) + n/4) + 2*n = 8*T(n/8) + 3*n
    4. = 8*(2*T(n/16) + n/8) + 3*n = 16*T(n/16) + 4*n
    5. ......
    6. = 2^k * T(n/2^k) + k * n
    7. ......

    通过这样一步一步分解推导,我们可以得到T(n) = 2^kT(n/2^k)+kn。当T(n/2^k)=T(1)时,也就是n/2^k=1,我们得到k=log2n 。我们将k值代入上面的公式,得到T(n)=Cn+nlog2n 。如果我们用大O标记法来表示的话,T(n)就等于O(nlogn)。所以归并排序的时间复杂度是O(nlogn)。

    空间复杂度就是O(nlogn)。

    快速排序

    递推公式

    1. 递推公式:
    2. quick_sort(p…r) = quick_sort(p…q-1) + quick_sort(q+1, r)
    3. 终止条件:
    4. p >= r

    将递推公式转化成递归代码。

    1. // 快速排序,A是数组,n表示数组的大小
    2. quick_sort(A, n) {
    3. quick_sort_c(A, 0, n-1)
    4. }
    5. // 快速排序递归函数,p,r为下标
    6. quick_sort_c(A, p, r) {
    7. if p >= r then return
    8. q = partition(A, p, r) // 获取分区点
    9. quick_sort_c(A, p, q-1)
    10. quick_sort_c(A, q+1, r)
    11. }

    最坏情况下的时间复杂度是O(n2),但是平均情况下时间复杂度都是O(nlogn

  • 相关阅读:
    iview表单提交验证特殊组件时需要注意的问题
    2 errors and 0 warnings potentially fixable with the `--fix` option.(Vue后台管理系统)
    AES(ECB/CBC) JS实现加密解密
    接口、压力测试工具入门指南
    机器视觉之工业摄像机知识点(二)
    Vue3+Element Plus使用svg加载iconfont的解决方案
    《Linux篇》超详细安装VMware与Linux教程
    JDBC技术(一)——一个简单的JDBC测试
    opencv c++ 实时对象追踪
    mysqldump 只导出数据 且非batch模式
  • 原文地址:https://blog.csdn.net/m0_63263973/article/details/126673184