超详解排序算法之(六)归并排序
程序员文章站
2022-06-04 10:05:59
...
归并排序
归并排序简介
归并排序是利用归并的思想实现排序的方法,这个排序算法采用了经典的分治策略【所谓分治法,先将问题***分***成一些小的问题然后递归求解,***治***的处理是将分的阶段中得到的各个答案“修补”在一起,从而实现分而治之。 】
看图释义
我们第一步递归的将原始数组分为不可再分的单元
第二步,归并到一起是归并算法的精髓,我们从最小单元开始合并,每一次合并就是一次有序化。通过log2N次归并处理就得到我们的有序化序列。
代码实现
最终结果代码
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 array 原始数组
* @param left 左边有序序列的初始索引
* @param mid 中间索引
* @param right 右边索引
* @param temp 临时数组
*/
public static void merge(int[] array,int left,int mid,int right,int[] temp){
int i=left; //左边数组的初始下标
int j=mid+1; //右边数组的初始下标
int t=0;//指向temp数组的当前索引
//(一)
//先把左右两边有序数组按照柜子额填充到temp数组
while (i<= mid && j <=right){
if(array[i]<=array[j]){
temp[t]=array[i];
i++;
t++;
}
else {
temp[t]=array[j];
j++;
t++;
}
}
//(二)
// 把有剩余数据的一边的数据一次填充到temp中去
while(i<=mid){
temp[t]=array[i];
t++;
i++;
}
while(j<=right){
temp[t]=array[j];
t++;
j++;
}
//(三)
// 把temp拷贝到array中去
t=0;
int tempLeft=left;
while (tempLeft<=right){
array[tempLeft]=temp[t];
t+=1;
tempLeft+=1;
}
}
}
代码实现过程详解
先进行分组
分组第一步我们先获取一个中间位置的元素,将元素分组,分的步骤实现,当每一个分组都不可再分,也就是说对于当前的分组左下标不小于右下标的时候这个分组就不可再分【递归的基准条件】
/**
*
* @param arr 原始数组
* @param left 组内左下标
* @param right 组内右下标
* @param temp 临时数组
*/
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 array 原始数组
* @param left 左边有序序列的初始索引
* @param mid 中间索引
* @param right 右边索引
* @param temp 临时数组
*/
public static void merge(int[] array,int left,int mid,int right,int[] temp){
int i=left; //左边数组的初始下标
int j=mid+1; //右边数组的初始下标
int t=0;//指向temp数组的当前索引
//(一)
//先把左右两边有序数组按照柜子额填充到temp数组
while (i<= mid && j <=right){
if(array[i]<=array[j]){
temp[t]=array[i];
i++;
t++;
}
else {
temp[t]=array[j];
j++;
t++;
}
}
//(二)
// 把有剩余数据的一边的数据一次填充到temp中去
while(i<=mid){
temp[t]=array[i];
t++;
i++;
}
while(j<=right){
temp[t]=array[j];
t++;
j++;
}
//(三)
// 把temp拷贝到array中去,注意一下这个处理,要涉及到其他分组的数量大于2的情况
t=0;
int tempLeft=left;
while (tempLeft<=right){
array[tempLeft]=temp[t];
t+=1;
tempLeft+=1;
}
}
测试结果
我们同样用8W个数据进行一把效率的验证
秒级的处理速度,感兴趣的小伙伴同样可以试试将时间显示为毫秒级查看一下。
另外将测试数据扩大10倍、100倍看看实际的耗时。
上一篇: 高楼寨之战的背景如何?起义军为什么对清*地方官吏极其痛恨?
下一篇: 头晕喝什么好,这些一定要试试