• 数据结构与算法(java版)第二季 - 3 归并排序


    目录

    归并排序(Merge Sort)

    merge细节

    merge情况的出现

    归并排序的复杂度

    常见递推式和复杂度


    归并排序(Merge Sort)

     1945年由约翰·冯·诺伊曼(John von Neumann)首次提出.

    首先对大佬表示缅怀,保佑我找到好工作.

    然后归并排序的过程是如下所示:

     执行流程:

    ① 不断地将当前序列平均分割成2个子序列---直到不能再分割(序列中只剩1个元素)
    ② 不断地将2个子序列合并成一个有序序列---直到最终只剩下1个有序序列

    merge细节

    需要merge的2个序列是存在于同一个数组之中,并且是挨在一起的.

    为了更好地完成 merge 操作,最好将其中 1 组序列备份出来,比如 [begin, mid) 

    首先进行相应的li的一个赋值,相应的li=0,le=mid-begin.ri=mid,re=end.

    其中使用相应的ai代表往其中的位置进行一个覆盖的过程,过程是比较简单的,就是需要进行相应的逻辑分析.

    merge情况的出现

    当左边是提前结束的,那么是就是右边是什么也不用干的

    当右边是提前结束的,左边是仍然是需要进行一个拿出的过程.

    具体实现的代码如下所示:

    1. public class MergeSort extends Comparable> extends Sort{
    2. private E[] leftArray;
    3. protected void sort() {
    4. leftArray = (E[]) new Object[array.length >> 1];
    5. sort(0,array.length);
    6. //[0,array.lenth)
    7. //[0,array.lenth>>1) [array.length>>1,array.length)
    8. }
    9. /**
    10. * 对[begin,end)范围内的数据进行一个归并排序
    11. *
    12. */
    13. //首先进行的是devide
    14. private void sort(int begin,int end)
    15. {
    16. if(end - begin < 2) return;
    17. int mid = (begin+end)>>1;
    18. sort(begin,mid);
    19. sort(mid,end);
    20. merge(begin,mid,end);
    21. }
    22. /**
    23. * 将[begin,mid)和[mid,end)范围进行一个合并的过程
    24. */
    25. private void merge(int begin,int mid,int end)
    26. {
    27. int li = 0,le = mid -begin;//左边
    28. int ri = mid,re = end;//右边
    29. int ai = begin;//对于右边的起始进行一个初始化的过程,这里应当是从begin开始的,老师这个地方出现了问题.
    30. //备份左边的数组
    31. for (int i = li;i < le;i++)
    32. {
    33. leftArray[i] = (E) array[begin + i];//这里应当注意的是相应的begin + i的原因
    34. }
    35. //只有是左边是没有结束的情况下,进行相应的操作(进行比对的前提)
    36. //如果左边是没有结束的
    37. while(li < le)
    38. {
    39. if(cmp((Integer) leftArray[li],array[ri]) > 0 && ri < re)
    40. {
    41. array[ai++] = (Integer) leftArray[li++];
    42. }
    43. else
    44. {
    45. array[ai++] = array[ri++];
    46. }
    47. }
    48. }
    49. }

    归并排序的复杂度

    归并排序花费的时间
    T (n) = 2 ∗ T(n/2) + O(n)
    T (1) = O(1)
    T (n)/n = T (n/2) /(n/2) + O(1)[基本的数学变换过程]
    S (n) = T (n)/n
    S (1) = O(1)
    S (n) = S (n/2) + O(1) = S (n/4) + O(2) = S (n/8) + O(3) = S (n/2 k)  + O (k) = S (1) + O(logn) = O(logn)
    T (n) = (n) ∗ S (n) = O(nlogn)
    由于归并排序总是平均分割子序列,所以最好、最坏、平均时间复杂度都是 O(nlogn) ,属于稳定排序
    从代码中不难看出:归并排序的空间复杂度是 O (n/2 + logn )= O(n)[注意理解(这个地方非常不好想)]
    n/2 用于临时存放左侧数组, logn 是因为递归调用

    常见递推式和复杂度

  • 相关阅读:
    机器内存充足,Java程序却报native内存OOM的问题记录
    sql server如主键创建时候没有命名,如何利用sql语句删除呢?
    说说前端经常考的手写题
    JAVA:实现Prim求最小生成树MST算法(附完整源码)
    BFM模型和Landmarks可视化
    科技云报道:Citrix正式退出中国市场!国产们谁能真正顶上?
    强化学习 DQN 经验回放 是什么
    Windows环境下的ELK——搭建环境(1)
    Docker镜像管理基础
    WifiCountryCode&信道
  • 原文地址:https://blog.csdn.net/m0_47489229/article/details/126687710