|
16 | 16 |
|
17 | 17 | public class Code_0014_MergeSort {
|
18 | 18 |
|
19 | | - // merge sort的递归写法 |
20 | | - public static void sort(int[] arr) { |
21 | | - mergeSort(arr, 0, arr.length - 1); |
22 | | - } |
23 | | - |
24 | | - // 递归解法 |
25 | | - public static void mergeSort(int[] arr, int l, int r) { |
26 | | - if (l >= r) { |
27 | | - // 终止条件 |
28 | | - return; |
29 | | - } |
30 | | - int mid = l + ((r - l) >> 1); |
31 | | - mergeSort(arr, l, mid); |
32 | | - mergeSort(arr, mid + 1, r); |
33 | | - merge2(arr, l, mid, r); |
34 | | - } |
35 | | - |
36 | | - public static void merge2(int[] arr, int l, int m, int r) { |
37 | | - int[] help = new int[r - l + 1]; |
38 | | - int s = l; |
39 | | - int e = m + 1; |
40 | | - int i = 0; |
41 | | - while (s <= m && e <= r) { |
42 | | - if (arr[s] <= arr[e]) { |
43 | | - help[i++] = arr[s++]; |
44 | | - } else { |
45 | | - help[i++] = arr[e++]; |
46 | | - } |
47 | | - } |
48 | | - while (s <= m) { |
49 | | - help[i++] = arr[s++]; |
50 | | - } |
51 | | - while (e <= r) { |
52 | | - help[i++] = arr[e++]; |
53 | | - } |
54 | | - for (i = 0; i < help.length; i++) { |
55 | | - arr[l++] = help[i]; |
56 | | - } |
57 | | - } |
58 | | - |
59 | | - // 迭代版本的merge sort |
60 | | - public static void mergeSort2(int[] arr, int l, int r) { |
61 | | - if (arr == null || arr.length < 2) { |
62 | | - return; |
63 | | - } |
64 | | - |
65 | | - int n = arr.length; |
66 | | - |
67 | | - // 1. 外层循环:控制每次要合并的子数组的大小(subArraySize) |
68 | | - // subArraySize 从 1 开始,每次翻倍,表示当前有序子数组的长度 |
69 | | - // 依次为 1, 2, 4, 8, ... |
70 | | - for (int subArraySize = 1; subArraySize < n; subArraySize = subArraySize * 2) { |
71 | | - |
72 | | - // 2. 内层循环:从左到右,找到每一对需要合并的子数组,然后调用merge |
73 | | - // leftStart 是每一对子数组中,左边那个数组的起始位置 |
74 | | - for (int leftStart = 0; leftStart < n; leftStart = leftStart + subArraySize * 2) { |
75 | | - |
76 | | - // 确定左子数组的边界 |
77 | | - // 左数组是 arr[leftStart ... mid] |
78 | | - int mid = leftStart + subArraySize - 1; |
79 | | - |
80 | | - // 如果 mid 已经越界,说明在 leftStart 之后连一个完整的左数组都凑不齐了 |
81 | | - // 那么剩下的部分自然就是有序的,无需再合并,直接跳出内层循环 |
82 | | - if (mid >= n - 1) { |
83 | | - break; |
84 | | - } |
85 | | - |
86 | | - // 确定右子数组的边界 |
87 | | - // 右数组是 arr[mid + 1 ... rightEnd] |
88 | | - // 这里用 Math.min 是为了防止右边界越界 |
89 | | - // 比如数组长度为13,当合并size=4的子数组时,最后一组是 arr[8...11] 和 arr[12...12] |
90 | | - // 此时 rightEnd 就不能是 8 + 4*2 - 1 = 15,而应该是 n - 1 = 12 |
91 | | - int rightEnd = Math.min(leftStart + subArraySize * 2 - 1, n - 1); |
92 | | - |
93 | | - // 找到了左右两个要合并的有序子数组,执行合并 |
94 | | - // System.out.printf("合并: subArraySize=%d, merge(arr, %d, %d, %d)%n", subArraySize, leftStart, mid, rightEnd); |
95 | | - merge(arr, leftStart, mid, rightEnd); |
96 | | - } |
97 | | - // System.out.println("--- subArraySize=" + subArraySize + " 的一轮合并结束 ---"); |
98 | | - } |
99 | | - } |
100 | | - |
101 | | - private static void merge(int[] arr, int l, int m, int r) { |
102 | | - int i = 0; |
103 | | - int s = l; |
104 | | - int e = m + 1; |
105 | | - int[] help = new int[r - l + 1]; |
106 | | - while (s <= m && e <= r) { |
107 | | - if (arr[s] <= arr[e]) { |
108 | | - help[i++] = arr[s++]; |
109 | | - } else { |
110 | | - help[i++] = arr[e++]; |
111 | | - } |
112 | | - } |
113 | | - while (s <= m) { |
114 | | - help[i++] = arr[s++]; |
115 | | - } |
116 | | - |
117 | | - while (e <= r) { |
118 | | - help[i++] = arr[e++]; |
119 | | - } |
120 | | - for (i = 0; i < help.length; i++) { |
121 | | - arr[l++] = help[i]; |
122 | | - } |
123 | | - } |
124 | | - |
125 | | - public static void swap(int[] arr, int i, int j) { |
126 | | - if (null == arr || arr.length <= 1) { |
127 | | - return; |
128 | | - } |
129 | | - int tmp = arr[i]; |
130 | | - arr[i] = arr[j]; |
131 | | - arr[j] = tmp; |
132 | | - } |
133 | | - |
134 | | - public static void main(String[] args) { |
135 | | - |
136 | | - // 数组长度1~500,等概率随机 |
137 | | - int num = 500; |
138 | | - // 每个值的大小在1~1024,等概率随机 |
139 | | - int value = 1024; |
140 | | - // 测试次数 |
141 | | - int testTimes = 50000; |
142 | | - System.out.println("测试开始"); |
143 | | - for (int i = 0; i < testTimes; i++) { |
144 | | - int[] arr = generateArray(num, value); |
145 | | - int[] copyArray1 = copyArray(arr); |
146 | | - int[] copyArray2 = copyArray(arr); |
147 | | - Arrays.sort(arr); |
148 | | - sort(copyArray1); |
149 | | - mergeSort2(copyArray2, 0, copyArray2.length - 1); |
150 | | - if (!sameValue(arr, copyArray1)) { |
151 | | - System.out.println("出错了!"); |
152 | | - break; |
153 | | - } |
154 | | - if (!sameValue(arr, copyArray2)) { |
155 | | - System.out.println("出错了!"); |
156 | | - break; |
157 | | - } |
158 | | - } |
159 | | - System.out.println("测试结束"); |
160 | | - } |
161 | | - |
162 | | - private static boolean sameValue(int[] arr1, int[] arr2) { |
163 | | - if (null == arr1) { |
164 | | - return null != arr2; |
165 | | - } |
166 | | - if (null == arr2) { |
167 | | - return null != arr1; |
168 | | - } |
169 | | - if (arr1.length != arr2.length) { |
170 | | - return false; |
171 | | - } |
172 | | - for (int i = 0; i < arr1.length; i++) { |
173 | | - if (arr1[i] != arr2[i]) { |
174 | | - return false; |
175 | | - } |
176 | | - } |
177 | | - return true; |
178 | | - } |
179 | | - |
180 | | - private static int[] generateArray(int num, int value) { |
181 | | - int[] arr = new int[(int) (Math.random() * num) + 1]; |
182 | | - for (int i = 0; i < arr.length; i++) { |
183 | | - arr[i] = (int) (Math.random() * value) + 1; |
184 | | - } |
185 | | - return arr; |
186 | | - } |
187 | | - |
188 | | - private static int[] copyArray(int[] arr) { |
189 | | - int[] copyArray = new int[arr.length]; |
190 | | - System.arraycopy(arr, 0, copyArray, 0, copyArray.length); |
191 | | - return copyArray; |
192 | | - } |
| 19 | + // merge sort的递归写法 |
| 20 | + public static void sort(int[] arr) { |
| 21 | + mergeSort(arr, 0, arr.length - 1); |
| 22 | + } |
| 23 | + |
| 24 | + // 递归解法 |
| 25 | + public static void mergeSort(int[] arr, int l, int r) { |
| 26 | + if (l >= r) { |
| 27 | + // 终止条件 |
| 28 | + return; |
| 29 | + } |
| 30 | + int mid = l + ((r - l) >> 1); |
| 31 | + mergeSort(arr, l, mid); |
| 32 | + mergeSort(arr, mid + 1, r); |
| 33 | + merge(arr, l, mid, r); |
| 34 | + } |
| 35 | + |
| 36 | + public static void merge(int[] arr, int l, int m, int r) { |
| 37 | + int[] help = new int[r - l + 1]; |
| 38 | + int s = l; |
| 39 | + int e = m + 1; |
| 40 | + int i = 0; |
| 41 | + while (s <= m && e <= r) { |
| 42 | + if (arr[s] <= arr[e]) { |
| 43 | + help[i++] = arr[s++]; |
| 44 | + } else { |
| 45 | + help[i++] = arr[e++]; |
| 46 | + } |
| 47 | + } |
| 48 | + while (s <= m) { |
| 49 | + help[i++] = arr[s++]; |
| 50 | + } |
| 51 | + while (e <= r) { |
| 52 | + help[i++] = arr[e++]; |
| 53 | + } |
| 54 | + for (i = 0; i < help.length; i++) { |
| 55 | + arr[l++] = help[i]; |
| 56 | + } |
| 57 | + } |
| 58 | + |
| 59 | + // 迭代版本的merge sort |
| 60 | + public static void sort2(int[] arr) { |
| 61 | + if (arr == null || arr.length < 2) { |
| 62 | + return; |
| 63 | + } |
| 64 | + int n = arr.length; |
| 65 | + for (int subSize = 1; subSize < n; subSize <<= 1) { |
| 66 | + // 每组1,2,4,8这样扩 |
| 67 | + for (int leftIndex = 0; leftIndex < n; leftIndex = leftIndex + (subSize * 2)) { |
| 68 | + // 第一组的起始位置 |
| 69 | + int m = leftIndex + subSize - 1; |
| 70 | + if (m >= n - 1) { |
| 71 | + // 没有右组,已经排好了 |
| 72 | + break; |
| 73 | + } |
| 74 | + int rightEnd = Math.min(leftIndex + (subSize * 2) - 1, n - 1); |
| 75 | + merge(arr, leftIndex, m, rightEnd); |
| 76 | + } |
| 77 | + } |
| 78 | + } |
| 79 | + |
| 80 | + public static void swap(int[] arr, int i, int j) { |
| 81 | + if (null == arr || arr.length <= 1) { |
| 82 | + return; |
| 83 | + } |
| 84 | + int tmp = arr[i]; |
| 85 | + arr[i] = arr[j]; |
| 86 | + arr[j] = tmp; |
| 87 | + } |
| 88 | + |
| 89 | + public static void main(String[] args) { |
| 90 | + |
| 91 | + // 数组长度1~500,等概率随机 |
| 92 | + int num = 500; |
| 93 | + // 每个值的大小在1~1024,等概率随机 |
| 94 | + int value = 1024; |
| 95 | + // 测试次数 |
| 96 | + int testTimes = 50000; |
| 97 | + System.out.println("测试开始"); |
| 98 | + for (int i = 0; i < testTimes; i++) { |
| 99 | + int[] arr = generateArray(num, value); |
| 100 | + int[] copyArray1 = copyArray(arr); |
| 101 | + int[] copyArray2 = copyArray(arr); |
| 102 | + Arrays.sort(arr); |
| 103 | + sort(copyArray1); |
| 104 | + sort2(copyArray2); |
| 105 | + if (!sameValue(arr, copyArray1)) { |
| 106 | + System.out.println("出错了!"); |
| 107 | + break; |
| 108 | + } |
| 109 | + if (!sameValue(arr, copyArray2)) { |
| 110 | + System.out.println("出错了!"); |
| 111 | + break; |
| 112 | + } |
| 113 | + } |
| 114 | + System.out.println("测试结束"); |
| 115 | + } |
| 116 | + |
| 117 | + private static boolean sameValue(int[] arr1, int[] arr2) { |
| 118 | + if (null == arr1) { |
| 119 | + return null != arr2; |
| 120 | + } |
| 121 | + if (null == arr2) { |
| 122 | + return null != arr1; |
| 123 | + } |
| 124 | + if (arr1.length != arr2.length) { |
| 125 | + return false; |
| 126 | + } |
| 127 | + for (int i = 0; i < arr1.length; i++) { |
| 128 | + if (arr1[i] != arr2[i]) { |
| 129 | + return false; |
| 130 | + } |
| 131 | + } |
| 132 | + return true; |
| 133 | + } |
| 134 | + |
| 135 | + private static int[] generateArray(int num, int value) { |
| 136 | + int[] arr = new int[(int) (Math.random() * num) + 1]; |
| 137 | + for (int i = 0; i < arr.length; i++) { |
| 138 | + arr[i] = (int) (Math.random() * value) + 1; |
| 139 | + } |
| 140 | + return arr; |
| 141 | + } |
| 142 | + |
| 143 | + private static int[] copyArray(int[] arr) { |
| 144 | + int[] copyArray = new int[arr.length]; |
| 145 | + System.arraycopy(arr, 0, copyArray, 0, copyArray.length); |
| 146 | + return copyArray; |
| 147 | + } |
193 | 148 |
|
194 | 149 | }
|
0 commit comments