import java.util.Arrays;
import java.util.Random;
public class A009_归并排序 {
public static void main(String[] args) {
int len = 10;
int max = 20;
int[] arr = getRandomArr(len, max);
System.out.println(Arrays.toString(arr));
sort(arr, 0, len - 1);
System.out.println(Arrays.toString(arr));
}
public static void sort(int[] arr, int left, int right) {
if (left < right) {
int mid = (left + right) / 2;
sort(arr, left, mid);
sort(arr, mid + 1, right);
merge(arr, left, mid, right);
}
}
public static void merge(int[] arr, int left, int mid, int right) {
int[] help = new int[right + 1];
copy(arr, help, left, right);
System.out.println(Arrays.toString(help) + " " + left + " " + mid + " " + right);
int l = left;
int r = mid + 1;
int cur = left;
while (l <= mid && r <= right) {
if (help[l] <= help[r]) {
arr[cur] = help[l];
l++;
cur++;
} else {
arr[cur] = help[r];
r++;
cur++;
}
}
while (l <= mid) {
arr[cur] = help[l];
l++;
cur++;
}
while (r <= right) {
arr[cur] = help[r];
r++;
cur++;
}
}
public static void copy(int[] arr, int[] help, int p, int right) {
while (p <= right) {
help[p] = arr[p];
p++;
}
}
public static int[] getRandomArr(int len, int max) {
int[] arr = new int[len];
Random ran = new Random(max);
for (int i = 0; i < len; i++) {
arr[i] = ran.nextInt(max) + 1;
}
return arr;
}
}
这里还是用随机数来生成数组,然后是用递归进行层次划分,这里可以看图
归并排序是将数组中这一个段内的元素复制到一个新数组中,然后从两段数组的头读到元素,进行比较,这里对应的就是先用sort函数进行折半,在其返回的时候,进行合并,合并用到了merge。
我将merge的每一步的数组都打印了出来,方便查看,这里用copy函数,把arr数组中,left到right的所有值,都复制给help,可以看到打印出的help数组,有很多元素都是0,这个要对应着下一段看👇
可以看到,第一次的help数组只有两个元素,然后left、mid、right的值是0、0、1,也就是第一第二个元素,分别是第一段和第二段,然后对他们进行比较,并按顺序插入,然后之后的每一步都是这样;那么如果是0的话,就要再看3个下标的值了,可以观察一下,正数第四行的[0,0,0,2,6] 3 3 4,非0的那个下标,正好就是left=3,也就是说,并不会把前面的0,也加入到arr数组中,接下来讲循环。
第一个while循环是对两个指针都进行判断,比如,我们看倒数第三行[0, 0, 0, 0, 0, 14, 16, 16, 9, 14] 5 7 9,着两个数组是
A:14,16,16
B:9,14
这时候还要看l和r,他们分别对应的值是5和8,也就是A的第一个元素,和B的第一个元素,把这两个进行比较,那么就是把B的第一个元素放入arr数组中了,那么这时候,cur 的下标就是left,也就是5,放进去之后,l++还有cur++;之后也是反复,那么接下来要讲另一种情况;
同样也是上面的A,B例子当这个循环进行完后,B的元素先被放完,这时候,A中还有剩余的元素没放进arr数组,那么就用到了下面的两个循环,哪一组没放进去,那就把那一组的剩下的所有值,都放进去,其实与第一个循环相差没多少。
那么这就是完整的归并排序了,代码看着多,但也是重复的部分比较多。