生活日用算法——归并排序的java实现

最近在看sort在1.7下的源码,发现在排序元素少于32的时候,使用的是Meger sort优化版——TimSort。本着溯本求源的精神,我先去看了下归并排序在JAVA的实现,虽然一直以来对归并排序的原理清楚的,但不曾自己写过。网上找了别人实现好的代码,然后自己理解后填上了注释,记录如下以供日后回顾(此代码的尾递归理论上可以转为迭代,以减少空间使用,防止栈的溢出)

 

首先,这里有一个基础的merge算法,实现对两个有序数组的合并。

 1 /**
 2      * 将两个有序数组合并为一个(递增)  此处略微取巧,两个有序数组分别为a[beginFrist,beginSecond)与[beginSecond,endSecond]
 3      * @param a              指定数组A
 4      * @param beginFrist     第一个有序数组的开始位置
 5      * @param beginSecond    第一个有序数组的结束位置(第二个有序数组的开始位置)
 6      * @param endSecond      第二个有序数组的结束为止
 7      */
 8     private static void merge(int[] a, int beginFrist, int beginSecond, int endSecond) {
 9         //建立一个中间数组,用于存放这两个有序数组合并后的有序数组数据
10         int[] tmp = new int[endSecond - beginFrist + 1];
11         //初始化各中间变量
12         int tempFristLocation = beginFrist, tempSecondLocation= beginSecond, tempLocation = 0;
13         //遍历两个数组,并排序,知道一个数组被全部遍历为止。
14         while (tempFristLocation < beginSecond && tempSecondLocation <= endSecond) {
15             if (a[tempFristLocation] <= a[tempSecondLocation]) {
16                 tmp[tempLocation] = a[tempFristLocation];   
17                 tempFristLocation++;
18             } else {
19                 tmp[tempLocation] = a[tempSecondLocation];
20                 tempSecondLocation++;
21             }
22             tempLocation++;
23         }
24         //把另一个为被完全遍历的数组剩余部分加在temp最后,因为两个数组本身有序,所以剩余部分一定比现有部分大。
25         while (tempFristLocation < beginSecond) {
26             tmp[tempLocation] = a[tempFristLocation];
27             tempFristLocation++;
28             tempLocation++;
29         }
30         while (tempSecondLocation <= endSecond) {
31             tmp[tempLocation] = a[tempSecondLocation];
32             tempSecondLocation++;
33             tempLocation++;
34         }
35         //复制temp到给的数组a
36         System.arraycopy(tmp, 0, a, beginFrist, tmp.length);
37     }

 

归并主算法如下:

 1     /**
 2      * 归并主算法,此处使用了尾递归,理论上可转换为迭代
 3      * @param a        需排序数组
 4      * @param len      每个堆内的元素个数
 5      */
 6     public static void mergeSort(int[] a, int len) {
 7         //初始化数据
 8         int size = a.length,s;
 9         //取到中间位置,此处<<的位运算可理解为*2
10         int mid = size / (len << 1);
11         // 归并到只剩一个有序集合的时候结束算法
12         if (mid == 0)
13             return;
14         //进行一趟归并排序
15         for (int i = 0; i < mid; ++i) {
16             //s为第一个有序数组的开始位置
17             s = i * 2 * len;
18             //调用归并排序
19             merge(a, s, s + len, (len << 1) + s - 1);
20         }
21         /* 此处由于len一定为2的N次幂,所以对size与((len << 1) - 1)进行与运算,只要不为0即可代表size不是len的倍数,即len不能被zise整除
22                             也就是说, mid次归并后还有部分数据没有得到归并处理*/
23         int c = size & ((len << 1) - 1);
24 
25         //将剩下的数和最后一个有序集合归并
26         if (c != 0)
27             merge(a, size - c - 2 * len, size - c, size - 1);
28         // -------递归执行下一趟归并排序------//
29         mergeSort(a,  2 * len);
30     }

 

测试方法如下:

 1     public static void main(String[] args) {
 2         Random random = new Random();
 3         int[] a = new int[8];
 4         for (int i = 0; i < a.length; i++) {
 5             a[i]=random.nextInt(100);
 6         }
 7         mergeSort(a,  1);
 8         for (int i = 0; i < a.length; ++i) {
 9             System.out.print(a[i] + " ");
10         }
11     }

 

posted @ 2017-09-26 18:08  豆豆323  阅读(347)  评论(0编辑  收藏  举报