[排序算法]--归并排序的Java实现

不念不忘少年蓝@ 2022-07-12 01:17 299阅读 0赞

归并排序(2-路归并):归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用,归并排序将两个已排序的表合并成一个表。

下面先看一个归并排序过程的示例:
待排序列(14,12,15,13,11,16):
首先用分割的方法,将这个序列分割成一个个已经排好序的子序列,然后再利用归并的办法将一个个子序列合并成排好序的序列,如下图:
归并排序实例:

上面很明显就是采用先 “分割” 再 “合并” 的思想。我们首先把一个未排序的序列从中间分割成2部分,再把2部分分成4部分,依次分割下去,直到分割成一个一个的数据,再把这些数据两两归并到一起,使之有序,不停的归并,最后成为一个排好序的序列。

下面首先考虑怎么把两个有序的序列合并。这个非常简单,只要从比较二个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。源码如下:

  1. /** * 把有序数组a和有序数组b 合并到数组c中,这里假设数组c的容量足够大,可以容纳数组a和数组b中的所有元素。 * @param a * @param n 数组a的长度n * @param b * @param m 数组b的长度m * @param c */
  2. public static void mergeArray(int a[], int n, int b[], int m, int c[]){
  3. int i,j,k;
  4. //索引
  5. i=j=k=0;
  6. while (i < n && j < m){
  7. if(a[i] < b[j]){
  8. c[k++] = a[i++];
  9. } else {
  10. c[k++] = b[j++];
  11. }
  12. }
  13. //将数组a或则b中剩余的元素加入数组c中
  14. while (i<n){
  15. c[k++] = a[i++];
  16. }
  17. while (j < m){
  18. c[k++] = b[j++];
  19. }
  20. }//end

上面的合并算法的效率还是比较高的,可以达到O(n)的时间复杂度。

上面已经解决了合并有序序列的问题,下面再来看看二路归并的方法,其的基本思路就是将数组分成二组A,B,如果这二组组内的数据都是有序的,那么就可以很方便的将这二组数据进行排序。如何让这二组组内数据有序了?

可以将A,B组各自再分成二组。依次类推,当分出来的小组只有一个数据时,可以认为这个小组组内已经达到了有序,然后 再合并相邻的二个小组就可以了。这样通过先递归的分解数列,再合并数列就完成了归并排序。 源码如下:

  1. /** * 将a[first, mid] 和 a[mid+1, last] 合并 * @param a * @param first * @param mid * @param last * @param temp */
  2. private static void mergeArray(int a[], int first, int mid, int last, int temp[]){
  3. int i = first, j=mid+1;//设置两个数组的起始边界
  4. int m=mid, n=last;//设置两个数组的结束边界
  5. int k=0;
  6. while (i <= m && j<=n){
  7. if(a[i] <= a[j]){
  8. temp[k++] = a[i++];
  9. }else {
  10. temp[k++] = a[j++];
  11. }
  12. }
  13. while (i<=m){
  14. temp[k++] = a[i++];
  15. }
  16. while (j <= n){
  17. temp[k++] = a[j++];
  18. }
  19. for(i=0; i<k; i++){
  20. a[first+i] = temp[i];
  21. }
  22. }
  23. /** * 二路归并 使用递归解决. * @param a * @param first 数组的起始下标 * @param last 数组的结束下标 * @param temp 辅助数组 */
  24. public static void mergeSort(int[] a, int first, int last, int[] temp){
  25. if(first < last) {
  26. int mid = (first + last)/2;
  27. mergeSort(a, first, mid, temp);//左边有序
  28. mergeSort(a, mid+1, last, temp);//右边有序
  29. mergeArray(a, first, mid, last, temp); //再将两个有序序列合并.
  30. }
  31. }

测试:

  1. public static void main(String[] args) {
  2. int[] arr = {
  3. 1,9,3,12,7,8,3,4,65,22};
  4. int[] temp = {
  5. 0,0,0,0,0,0,0,0,0,0};
  6. mergeSort(arr, 0, arr.length-1, temp);
  7. for(int i:arr){
  8. System.out.print(i+",");
  9. }
  10. }

输出:

  1. 1,3,3,4,7,8,9,12,22,65,

归并排序的效率是比较高的,设数列长为N,将数列分开成小数列一共要logN步,每步都是一个合并有序数列的过程,时间复杂度可以记为O(N),故一共为O(N*logN)。因为归并排序每次都是在相邻的数据中进行操作,所以归并排序在O(N*logN)的几种排序方法(快速排序,归并排序,希尔排序,堆排序)也是效率比较高的。

本文给出的是数组实现,下面也给出一个单链表实现的思路,其实就是leetcode的一个题目:
http://blog.csdn.net/u010853261/article/details/54884650

本文所有代码的github地址:
https://github.com/leetcode-hust/leetcode/blob/master/louyuting/src/leetcode/Algorithm/MergeSort.java

发表评论

表情:
评论列表 (有 0 条评论,299人围观)

还没有评论,来说两句吧...

相关阅读

    相关 排序算法——归并排序

    引言 归并排序可以使用递归或迭代的方式来实现,时间复杂度是都是 O(N \ logN)。 归并排序的核心是将待排序数组分组,可以整体二分,也可以设置步长迭代切分。归并排

    相关 排序算法-归并排序

    归并排序也是一个比较快速的排序算法,其思想是运用分治的思想,先对要排序的数进行分,每次从中间分成两部分,然后知道分成最小,然后在把他们合起来,边合起来边排序,最后有序,每次分的

    相关 归并排序算法Java实现

    1、基本思想 归并排序(Merge)是将两个(或两个以上)有序表合并成一个新的有序表,即把待排序序列分为若干个子序列,每个子序列是有序的。然后再把有序子序列合并为整体有序序列

    相关 排序算法归并排序Java实现

    归并排序的思想是将局部有序的数组合并为一个大的有序数组,前提是需要保证局部数组有序,如果局部没有顺序,那么就拆分,再合并,最差的情况是,拆到两个数组都只有一个元素的时候,这时候