Java实现归并排序
这个排序法看着挺简单的,但是写起来就不容易了,我也是弄了很久才想明白。
下面是图示:
这是合并的图示,分解则是反过来的。
思路:
把一个数组分解成两半,如果两半之后还能分则继续分解成两半,直到不能分解也就是一个数组分解成左边的下标等于右边的下标为止。分解完之后就比较最小的数组,合并成一个大一点的数组,以此类推。以上面的图做例子:分解得2 4 5 7和1 2 3 6———分解得2 5和4 7和1 3和2 6——分解得5 2 4 7 1 3 6 2——两两比较排序——两个数组两个数组比较排序,即2与4比较然后4与5比较然后5与7比较,以此类推排得2 4 5 7和1 2 3 6——两个数组比较得最后结果。(我刚开始也懂思路但是写出来还是用了很长时间,这中间也看了很多别人的代码都不太理解,可能还是我写的不够多吧)
import java.util.Scanner;
public class MergeSort {
public static void main(String[] args) {
// TODO Auto-generated method stub
System.out.println("请输入一个整数表示数列长度:");
Scanner sc = new Scanner(System.in);
int length = sc.nextInt();
System.out.println("请输入" + length + "个数:");
int[] arr = new int[length];
for (int i = 0; i < arr.length; i++) {
arr[i] = sc.nextInt();
}
Sort(arr, 0, arr.length - 1);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
// 将数组分解
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);// 把右边的数组分解
MergeSort(arr, left, right, mid);// 这里的right为要合并的数组的最右边的数的下标,不能写arr.length-1,否则会一直都是一样的,相反也一样
}
}
// 将数组合并
public static void MergeSort(int[] arr, int left, int right, int mid) {
int[] temp = new int[arr.length];// 用来存放合并后的数组
int i = left;
int j = mid + 1;
int k = left;// 合并多次,要从上一次已经合并好放进temp数组里的下标开始
while (i <= mid && j <= right) {
// 分解出来的数组从前面开始比较,如果前面的数组大于后面的数组则先放后面的数组到新的数组,放完的数组和被放数的数组指针都要往后移,相反也一样
if (arr[i] > arr[j]) {
temp[k++] = arr[j++];
} else {
temp[k++] = arr[i++];
}
}
// 如果最后执行完左边还有数就把左边的移到合并后的数组
while (i <= mid) {
temp[k++] = arr[i++];
}
// 如果最后执行完右边还有数就把右边的移到合并后的数组
while (j <= right) {
temp[k++] = arr[j++];
}
/*第一次执行完后temp的值只是左边最小的数组的,剩余的还没有赋值皆为0,如果t<arr.length,此时会使得arr除了左边的最小数组外皆为0
当执行到右边的时候也应该从右边的数组的最左边的数的下标开始而不是从0,否则会把temp[0]的值赋给arr[0],因为每次执行这个方法的时候都会初始化temp数组,合并哪里就应该从哪里开始赋值*/
//把数组赋值到原数组
for (int t = left; t <= right; t++) {
arr[t] = temp[t];
}
}
}