Java中的十大排序(八)归并排序

111 阅读2分钟

「这是我参与2022首次更文挑战的第14天,活动详情查看:2022首次更文挑战」。

前言

上一章节讲述了快速排序, 回顾上次快速排序他采用了双指针的思想来进行排序,而这次我们所讲述的归并排序使用了另一种方法来实现,对于以前的排序方法他们的空间利用都不会很大,但是归并是唯一一个空间占用很高的一个排序算法,其实有一点空间换时间的味道。

image.png

归并排序分析

平均时间复杂度 O(nlog下标2 n) 时间复杂度最坏 O(nlog下标2 n) 时间复杂度最好 O(nlog下标2 n) 空间复杂度为 o(n) 稳定性为稳定

通过上面参数发现归并排序的各方面时间都非常优秀,在众多排序算法中属于是佼佼者了,但是归并在弓箭复杂度上的占用比其他排序会多一点,因为在排序过程中归并需要不断地创建外部空间来实现,对于巨大的数据量归并就显得不是那么的合适了,有可能还会造成栈溢问题。

归并排序思路

经过上述分析后我们讲一下归并排序的实现思路,归并排序使用的思想主要是分治和递归,分治意思是分而治之,也就是大事化小、小事化了,来进行分开治理。递归就是一直调用自己,递归要注意一个点就是递归一定要有一个临界点。这个临界点决定了递归什么时候停止,没有临界点和无限循环一样是没有尽头的。归并则是结合两者的特点来进行的排序,它先进行一个分组,每次对半分开直到每个元素都是一组后进行归并,归并的过程就是创建一个连续空间来存储元素,在存储过程中判断两个归并的数组的大小来依次进入这个新的数组,一直递归回去就完成了归并排序。

image.png

归并排序代码实现

/**
 * 归并排序
 */

@Test
public void testMergeSort(){
  mergeSort(arr, 0, arr.length - 1);
  System.out.println(getArr(arr));
}

public static int[] mergeSort(int[] a, int low, int high) {
  int mid = (low + high) / 2;
  if (low < high) {
    mergeSort(a, low, mid);
    mergeSort(a, mid + 1, high);
    //进行归并
    merge(a, low, mid, high);
  }
  return a;
}

public static void merge(int[] a, int low, int mid, int high) {
  int[] temp = new int[high - low + 1];
  int i = low;
  int j = mid + 1;
  int k = 0;
  // 转移元素进入temp新数组,这里temp也就是归并借助的空间,也是归并的空间换时间之处
  while (i <= mid && j <= high) {
    if (a[i] < a[j]) {
      temp[k++] = a[i++];
    } else {
      temp[k++] = a[j++];
    }
  }
  while (i <= mid) {
    temp[k++] = a[i++];
  }
  while (j <= high) {
    temp[k++] = a[j++];
  }
  for (int x = 0; x < temp.length; x++) {
    a[x + low] = temp[x];
  }
}