思想:将一个有序序列递归分割为一个个单一的数据,分到不可再分割之后就回退到上一步,将数据两两有序合并合并到一个临时数组中去,再将合并过去的数据拷贝到原来的数组中,以此类推,反递归到最开始的地方,序列就变成一个有序序列了。
第一步:分割数组
public static void MergeSort(int[] arr,int left,int right,int[] temp){
//当数组左下标比右下标小时,说明还没有分割到最小的,则继续左右递归分割,
if (left < right){
int mid = (left + right) / 2;
MergeSort(arr, left, mid, temp);
MergeSort(arr, mid + 1, right, temp);
//当前面的递归出来时,说明要么就是不能再分割了,要么就是已经合并完成,退出了递归,出现这两种情况之后
//我们要将它们继续合并。
Merge(arr,left,mid,right,temp);
}
}
第二步:合并数组
public static void Merge(int[] arr,int left,int mid,int right,int[] temp){
int i = left;//记录左边数据开始的位置
int j = mid + 1;//记录右边数据开始的位置
int t = 0;//记录temp数组中的位置
/*
* 1、先把比较左右两边的数据并添加到temp数组,直到一边数据完全被填充到temp数组
* */
while (i <= mid && j <= right){
if (arr[i] < arr[j]){
temp[t] = arr[i];
t += 1;
i += 1;
}else {
temp[t] = arr[j];
t += 1;
j += 1;
}
}
/*
* 2、此时将剩下的另一边的数据全部填充到temp
* */
while (i <= mid){
//说明左边的数据没有填充完,直接把左边的数据给填到temp中去
temp[t] = arr[i];
t += 1;
i += 1;
}
while (j <= right){
//说明右边的数据没有填充完,直接把右边的数据给填到temp中去
temp[t] = arr[j];
t += 1;
j += 1;
}
/*
* 3、将temp数据拷贝到arr数组
* 此处注意,这里只是将本次归并好的数据拷贝到arr数组,并不是将所有的数据拷贝
* */
t = 0;
int templeft = left;//记录的是原数组中开始合并数据的位置
//例如是原数组是int arr[] = {1,3,5,6,8,7}它第一次合并的是1、3,则left=,right=1
//到第二次的时候是将5和{1,3}合并,left=0,right=2;
//第三次将6和8合并,left=3,right=4;
//第四次时间7和{6,8}合并,left=3,right=5;
//第五次是将{1,3,5}和{6,7,8}合并,left=0,right=5,合并的次数是arr.length - 1;
while (templeft <= right){
arr[templeft] = temp[t];
t += 1;
templeft += 1;
}
}
完整代码
public class MergeTest {
public static void main(String[] args) {
//int arr[] = {1,3,5,6,8,4,7,2};
// 创建要给 80000 个的随机的数组
int[] arr = new int[80000000];
for (int i = 0; i < 80000000; i++) {
arr[i] = (int) (Math.random() * 80000000);
// 生成一个[0, 8000000) 数
}
int temp[] = new int[arr.length];
//System.out.println(Arrays.toString(arr));
System.out.println("排序前");
Date data1 = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1Str = simpleDateFormat.format(data1);
System.out.println("排序前的时间是=" + date1Str);
MergeTest.MergeSort(arr, 0, arr.length - 1, temp);
System.out.println("排序后");
Date data2 = new Date();
String date1Str2 = simpleDateFormat.format(data2);
System.out.println("排序后的时间是=" + date1Str2);
//System.out.println(Arrays.toString(arr));
}
public static void MergeSort(int[] arr,int left,int right,int[] temp){
if (left < right){
int mid = (left + right) / 2;
MergeSort(arr, left, mid, temp);
MergeSort(arr, mid + 1, right, temp);
Merge(arr,left,mid,right,temp);
}
}
/*
* 将分开的数据进行合并
* */
public static void Merge(int[] arr,int left,int mid,int right,int[] temp){
int i = left;//记录左边数据开始的位置
int j = mid + 1;//记录右边数据开始的位置
int t = 0;//记录temp数组中的位置
/*
* 1、先把比较左右两边的数据并添加到temp数组,直到一边完全填充到temp数组
* */
while (i <= mid && j <= right){
if (arr[i] < arr[j]){
temp[t] = arr[i];
t += 1;
i += 1;
}else {
temp[t] = arr[j];
t += 1;
j += 1;
}
}
/*
* 2、将剩下的另一边的数据全部填充到temp
* */
while (i <= mid){
//说明左边的数据没有填充完,直接把左边的数据给填到temp中去
temp[t] = arr[i];
t += 1;
i += 1;
}
while (j <= right){
//说明右边的数据没有填充完,直接把右边的数据给填到temp中去
temp[t] = arr[j];
t += 1;
j += 1;
}
/*
* 3、将temp数据拷贝到arr数组
* 此处注意,这里只是将本次归并好的数据拷贝到arr数组,并不是将所有的数据拷贝
* */
t = 0;
int templeft = left;
while (templeft <= right){
arr[templeft] = temp[t];
t += 1;
templeft += 1;
}
}
}