一.归并排序
是利用归并的思想实现的排序方法,该算法采用经典的分治策略(分治法将问题分成一些小的问题然后递归求解,而治的阶段则将分的阶段得到的各个答案修补在一起,即分而治之)
分得过程中,将每个元素拆分出来,通过合并,将其排序,最核心的部分在于治.
解释上图操作(这里将的是治这个阶段,讲解下最后一次合并):
- 定义了一个i,j分别指向两个有序的子序列的最前面,将i,j指向的数据做比较,将最小的那个数据指向temp数组,也就是临时数组
- 如果上述中是i最小,第二次就将i右移一次.假如说是j最小,同样的将j右移.这样就能比较第二次了
- 第二次继续比较i,j指向的数,如上图所示.
- 从上图中我们可以看到j已经指向了最后了,不能再继续右移了,那我们就将i指向的后面所有的数据直接复制到临时数组中
- 最后在临时数组中的数据复制到原来的数组
代码演示:
package com.qiu.sort;
import java.util.Arrays;
public class MergeSort {
public static void main(String[] args) {
int[] arr ={8,4,5,7,1,3,6,2};
//归并排序需要有一个额外的空间
int temp[] = new int[arr.length];
mergeSort(arr,0,arr.length-1,temp);
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);
}
}
//合并的方法
/**
*
* @param arr 排序的原始数组
* @param left 左边有序的初始索引
* @param mid 中间的索引
* @param right 右边有序的索引
* @param temp 做中转的数组
*/
public static void merge(int[] arr,int left,int mid,int right,int[] temp){
//初始化i,左边有序序列的初始索引
int i = left;
//初始化j,右边有序序列的初始索引
int j = mid+1;
//指向temp数组的当前索引
int t = 0;
//1.先把左右两边的数据,按规则填充到temp数组中去,直到左右两边的有序序列,有一方处理完毕,为止
while (i <= mid && j <= right){
//如果左边的有序序列的当前元素,小于等于右边有序序列的当前元素
//即将左边的元素拷贝到temp数组中去,同时将t和i后移
if (arr[i] <= arr[j]){
temp[t] = arr[i];
t += 1;
i += 1;
}else {
//反之,将右边有序的当前元素填充到temp数组中
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数组的元素拷贝到array中去
//注意并不是每次都考虑所有的
t = 0;
int tempLeft = left;
while(tempLeft <= right){
//第一次合并时tempLeft是为0的,right是1
//第二次合并时tempLeft是为2的,right是3
//第三次合并时tempLeft是为0的,right是3
//最后一次templeft=0,right为数组的长度-1
arr[tempLeft] = temp[t];
t += 1;
tempLeft += 1;
}
}
}
代码结果:
接下来就是运行多个数据进行时间测试:
代码:
public static void main(String[] args) {
// int[] arr ={8,4,5,7,1,3,6,2,9};
// //归并排序需要有一个额外的空间
// int temp[] = new int[arr.length];
// mergeSort(arr,0,arr.length-1,temp);
// System.out.println("排序后的数组为:"+ Arrays.toString(arr));
//测试一下快速排序的速度,给8w随机数组
int[] arr = new int[80000];
for (int i = 0; i < 80000; i++) {
arr[i] =(int)(Math.random()*80000000);
}
//测试排序时间
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr = format.format(date);
System.out.println("排序前的时间:"+dateStr);
int temp[] = new int[arr.length];
mergeSort(arr,0,arr.length-1,temp);
System.out.println("排序后的数组为:"+ Arrays.toString(arr));
Date date1 = new Date();
SimpleDateFormat format1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String dateStr1 = format1.format(date1);
System.out.println("排序后的时间:"+dateStr1);
}
结果:
结果还是非常快的.这就是用空间换取时间的好处了.