前言:
    因为排序的种类实在是太多了,放在一篇文章里显得过于冗杂,所以把简单的排序方法放在一起了。
    今天要说的是归并排序,之前我没有接触,或者用过这个排序方式,也可能是我孤陋寡闻了。
    归并排序是1945年由约翰·冯·诺伊曼(John von Neumann)首次提出 。
    原理:
    执行流程 ① 不断地将当前序列平均分割成2个子序列 直到不能再分割(序列中只剩1个元素); ② 不断地将2个子序列合并成一个有序序列 直到最终只剩下1个有序序列
    image.png
    归并排序的主要步骤分为两个部分,一个是分开,一个是合并

    示例:

    1. protected void sort() {
    2. leftArray = (T[]) new Comparable[array.length >> 1];
    3. sort(0, array.length);
    4. }
    5. // T(n) = T(n/2) + T(n/2) + O(n)
    6. /**
    7. * 对 [begin, end) 范围的数据进行归并排序
    8. */
    9. private void sort(int begin, int end) {
    10. if (end - begin < 2) return;
    11. int mid = (begin + end) >> 1;
    12. sort(begin, mid);
    13. sort(mid, end);
    14. merge(begin, mid, end);
    15. }

    当我们已经将数组切开之后,我们该考虑如何让数组有序的合并在一起。
    image.png
    我们将子数组开头第一个数字称之为索引,我们两两比较索引大小,将较小的索引提出,放到新的数组中,去除索引的组数下一位就是新的索引。
    但是,我们可能重新开辟一块新的空间来放置整理好后的数据; 需要 merge 的 2 组序列存在于同一个数组中,并且是挨在一起的,
    image.png
    为了更好地完成 merge 操作,最好将其中 1 组序列备份出来,比如 [begin, mid)
    image.png
    li == 0;le == mid – begin; ri == mid;re == end
    image.png
    我们排序到最后,两边数组总一个会先结束
    当左边先结束的
    image.png
    左边先结束,就是右边有剩余,我们不需要任何操作

    当右边先结束
    image.png
    右边先结束,就是左边有剩余,我们需要将左边剩余部分原封不动的转移过来。

    示例:

    1. private void merge(int begin, int mid, int end) {
    2. int li = 0, le = mid - begin;
    3. int ri = mid, re = end;
    4. int ai = begin;
    5. // 备份左边数组
    6. for (int i = li; i < le; i++) {
    7. leftArray[i] = array[begin + i];
    8. }
    9. // 如果左边还没有结束
    10. while (li < le) {
    11. if (ri < re && (array[ri]-leftArray[li]) < 0) {
    12. array[ai++] = array[ri++];
    13. } else {
    14. array[ai++] = leftArray[li++];
    15. }
    16. }
    17. }

    算法分析:
    ![C}M)4)8036PJVINRMB~9{L.png
    这是一段完整的归并排序代码,可以debug来查看代码运行过程,深入学习
    示例:

    1. public class test {
    2. private int[] leftArray;
    3. private int[] array={1,4,2,12,16,19,7,8,3,9};
    4. public static void main(String[] args) {
    5. test t=new test();
    6. t.sort();
    7. for(int i=0;i<t.array.length;i++){
    8. System.out.println(t.array[i]);
    9. }
    10. }
    11. protected void sort() {
    12. leftArray = new int[array.length >> 1];
    13. sort(0, array.length);
    14. }
    15. // T(n) = T(n/2) + T(n/2) + O(n)
    16. /**
    17. * 对 [begin, end) 范围的数据进行归并排序
    18. */
    19. private void sort(int begin, int end) {
    20. if (end - begin < 2) {return;}
    21. int mid = (begin + end) >> 1;
    22. sort(begin, mid);
    23. sort(mid, end);
    24. merge(begin, mid, end);
    25. }
    26. /**
    27. * 将 [begin, mid) 和 [mid, end) 范围的序列合并成一个有序序列
    28. */
    29. private void merge(int begin, int mid, int end) {
    30. int li = 0, le = mid - begin;
    31. int ri = mid, re = end;
    32. int ai = begin;
    33. // 备份左边数组
    34. for (int i = li; i < le; i++) {
    35. leftArray[i] = array[begin + i];
    36. }
    37. // 如果左边还没有结束
    38. while (li < le) {
    39. if (ri < re && (array[ri]-leftArray[li]) < 0) {
    40. array[ai++] = array[ri++];
    41. } else {
    42. array[ai++] = leftArray[li++];
    43. }
    44. }
    45. }
    46. }