|
| 1 | +package org.lhn.mergesort; |
| 2 | + |
| 3 | +import org.lhn.util.SortTestTools; |
| 4 | + |
| 5 | +/** |
| 6 | + * @author LiHaiNan |
| 7 | + * @version V1.0 |
| 8 | + * @Description: 归并排序(注意边界问题) |
| 9 | + * @date 下午 6:29 2017/10/16 0016 |
| 10 | + */ |
| 11 | +public class MergeSort { |
| 12 | + |
| 13 | + public static void main(String[] args) { |
| 14 | + System.out.println("**程序开始排序**"); |
| 15 | +// int[] arr = SortTestTools.randomArrayForInt(n, 0, n); |
| 16 | + int[] arr = {7, 9, 2, 1, 8}; |
| 17 | + int n = arr.length; |
| 18 | + SortTestTools.printArray(arr); |
| 19 | + long startTime = System.currentTimeMillis(); |
| 20 | + mergeSort(arr, n); |
| 21 | + long endTime = System.currentTimeMillis(); |
| 22 | + SortTestTools.printArray(arr); |
| 23 | + System.out.println("算法耗时:【" + (endTime - startTime) + "】毫秒"); |
| 24 | + } |
| 25 | + |
| 26 | + |
| 27 | + /** |
| 28 | + * @Title: mergeSort |
| 29 | + * @Description: 归并排序 |
| 30 | + * @Date:下午 6:37 2017/10/16 0016 |
| 31 | + * @author LiHaiNan |
| 32 | + * @param: int[] arr数组, int n数组长度 |
| 33 | + * @return: void |
| 34 | + */ |
| 35 | + private static void mergeSort(int[] arr, int n) { |
| 36 | + myMergeSort(arr, 0, n - 1); |
| 37 | + } |
| 38 | + |
| 39 | + /** |
| 40 | + * @Title: myMergeSort |
| 41 | + * @Description: 内部调用子函数,递归使用归并排序,对arr[start...end]的范围进行排序 |
| 42 | + * end定义:最后一个元素的位置,而不是最后一个元素后一个的位置。 |
| 43 | + * @Date:下午 6:30 2017/10/16 0016 |
| 44 | + * @author LiHaiNan |
| 45 | + * @param: int[] arr要排序的数组, |
| 46 | + * int start要处理数据段的开始位置, int end要处理数据段的结束位置 |
| 47 | + * @return: void |
| 48 | + */ |
| 49 | + private static void myMergeSort(int[] arr, int left, int right) { |
| 50 | + //1.对于一个递归函数来说,首先需要处理递归到底的情况 |
| 51 | + //2.left<right时,则至少存在两个元素,还需要进行二分 |
| 52 | + if (left >= right) { |
| 53 | + return; |
| 54 | + } |
| 55 | + //进行归并排序 |
| 56 | + //注意:当left,right比较大的时候进行相加可能会发生溢出现象 |
| 57 | + int mid = (left + right) / 2; |
| 58 | + //对分开的左右两个部分进行归并排序 |
| 59 | + //左部分 |
| 60 | + myMergeSort(arr, left, mid); |
| 61 | + //右部分 |
| 62 | + myMergeSort(arr, mid + 1, right); |
| 63 | + /*归并完成,进行merge操作*/ |
| 64 | + myMerge(arr, left, mid, right); |
| 65 | + } |
| 66 | + |
| 67 | + /** |
| 68 | + * @Title: myMerge |
| 69 | + * @Description: 将arr[start...mid]和arr[mid+1..end]两部分进行归并 |
| 70 | + * @Date:下午 6:48 2017/10/16 0016 |
| 71 | + * @author LiHaiNan |
| 72 | + * @param: int[] arr, int start, int mid, int end |
| 73 | + * @return: void |
| 74 | + */ |
| 75 | + private static void myMerge(int[] arr, int left, int mid, int right) { |
| 76 | + //创建一个临时数组 |
| 77 | + int[] temp = new int[right - left + 1]; |
| 78 | + //将目前所有需要处理的数组数据复制到temp类数组中 |
| 79 | + for (int i = left; i <= right; i++) { |
| 80 | + //注意:temp数组是从0开始的,而arr数组则是在start开始的 |
| 81 | + //所以需要处理下标偏移(i-start) |
| 82 | + temp[i - left] = arr[i]; |
| 83 | + } |
| 84 | + //两个下标分别指向两部分的开始位置 |
| 85 | + int i = left, j = mid + 1; |
| 86 | + for (int k = left; k <= right; k++) { |
| 87 | + //判断索引的合法性 |
| 88 | + if (i > mid) { |
| 89 | + arr[k] = temp[j - left]; |
| 90 | + j++; |
| 91 | + } else if (j > right) { |
| 92 | + arr[k] = temp[i - left]; |
| 93 | + i++; |
| 94 | + } |
| 95 | + /*如何上述两个条件都不满足,进而才是有效的*/ |
| 96 | + //每一次决定arr[K]的位置应该是谁 |
| 97 | + else if (arr[i - left] < arr[j - left]) { |
| 98 | + arr[k] = temp[i - left]; |
| 99 | + i++; |
| 100 | + } else { |
| 101 | + arr[k] = temp[j - left]; |
| 102 | + j++; |
| 103 | + } |
| 104 | + } |
| 105 | + } |
| 106 | +} |
0 commit comments