:归并排序
- 归并排序是建立在归并操作上的一种有效,稳定的排序算法,该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
- 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
- 若将两个有序表合并成一个有序表,称为二路归并。
图片链接https://www.runoob.com/wp-content/uploads/2019/03/mergeSort.gif
package com.atguigu.sort;
import java.text.SimpleDateFormat;
import java.time.Clock;
import java.util.Arrays;
import java.util.Date;
//归并排序
public class MergeSort {
public static void main(String[] args) {
//
int[] arr = {8,4,5,7,1,3,6,2};//8->merge 7 // 80000 -> 80000-1
int temp[] = new int[arr.length];//归并排序需要一个额外空间
System.out.println("归并排序前:"+Arrays.toString(arr));
mergeSort(arr, 0, arr.length-1, temp);
System.out.println("归并排序后:"+Arrays.toString(arr));
timeSort();
}
//分+合 方法
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);
}
}
//合并的方法
/**
* @param arr 排序的原始数组
* @param left 左边有序序列的初始索引
* @param mid 中间索引
* @param right 右边索引
* @param temp 作为中转的数组
*/
public static void merge(int[] arr,int left,int mid,int right,int[] temp) {
// System.out.println("xxx");
int i = left;//初始化i,左边有序序列的初始索引
int j = mid + 1;//初始化j,右边有序序列的初始索引
int t = 0;// 指向temp数组的当前索引
//(一) 先把左右两边(有序)的数据按照规则填充到temp数组
//直到左右两边的有序数组,有一边被处理完毕(全部插入到了临时数组temp)
while(i<=mid && j<=right) {
//如果左边的有序序列的当前元素,小于右边有序序列的当前元素
//则将左边的当前元素,添加到temp数组,然后 t++ ,i++
if(arr[i]<=arr[j]) {
temp[t] = arr[i];
i++;
t++;
}else {//反之,将右边的当前元素,添加到temp数组,然后 t++ ,j++
temp[t] = arr[j];
j++;
t++;
}
}
//(二)
//把剩余数据一边数据依次填充到temp
while(i<=mid) {//左边的有序序列还有剩余
temp[t] = arr[i];
t++;
i++;
}
while(j<=right) {//右边的有序序列还有剩余
temp[t] = arr[j];
t++;
j++;
}
//(三)
//将temp数组的元素拷贝到arr
//注意:并不是每次都拷贝所有
t = 0;
int tempLeft = left;//
//第一次合并tempLeft=0,right=1 // 第二次tL=2, right=3 //第三次 tL=0,right=3
//最后一次合并 templeft =0,right =7;
// System.out.println("tempLeft:"+tempLeft+"right:"+right);
while(tempLeft <= right) {
arr[tempLeft] = temp[t];
t += 1;
tempLeft += 1;
}
}
// 耗时测试
public static void timeSort() {
// 测试排序的速度(O(n^2)),给80000个数据
// 创建一个80000个随机数的数组
int[] arr = new int[8000000];
int temp[] = new int[arr.length];//归并排序需要一个额外空间
for (int i = 0; i < 8000000; i++) {
arr[i] = (int) (Math.random() * 8000000);// 生成一个【0,8000000】数
}
Date data1 = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1Str = simpleDateFormat.format(data1);
System.out.println("800万个随机数据-排序前的时间是: " + date1Str);
//获取排序前时间
long s = Clock.systemDefaultZone().millis();
mergeSort(arr,0,arr.length-1,temp);
//打印 八万个随机数据【希尔排序-交换法】 总耗时间
System.out.println("800万个随机数据【归并排序】耗时: " + (Clock.systemDefaultZone().millis() - s) + " ms");
Date data2 = new Date();
String date2Str = simpleDateFormat.format(data2);
System.out.println("800万个随机数据-排序后的时间是: " + date2Str);
}
}