好长时间没有更新了,有没有想我呢?我们接着说排序算法吧
今天为大家梳理的是归并排序
合并排序(Merge Sort)算法就是将多个有序数据表合并成一个有序数据表。如果参与合并的只有两个有序表,则称为二路合并。对于一个原始的待排序序列,往往可以通过分割的方法来归结为多路合并排序。下面以二路合并为例,来介绍合并排序算法。
合并排序算法
一个待排序的原始数据序列进行合并排序的基本思路是,首先将含有n个结点的待排序数称列看作由n个长度为1的有序子表组成,将其依次两两合并,得到长度为2的若干有序子表:然后,再对这些子表进行两两合并,得到长度为4的若干有序子表.…,重复上述过程,一直到最后的子表长度为n,从而完成排序过程。
1.合并排序算法原理
下面通过一个实际的例子来分析合并排序算法的执行过程,以加深读者的理解。
假设有9个需要排序的数据序列 67、65、77、38、97、3、33、49、34。合并排序算法的操作步骤如下:
(1)首先将9个原始数据看成9个长度为1的有序子表。每一个子表中只有一个数据,这里可以认为单个数据是有序的。
(2)将这9个有序子表两两合并,为了方便,将相邻的子表进行两两合并。例如,将第1、2个合并在一起,第3、4个合在一起···,最后一个没有合并的,就单独放在那里,直接进入下一遍合并,如图所示。
原始数据:
(3)经过第1遍的合并,得到长度为2的有序表序到,再将这些长度为2的有序却学。
两合并,如图所示。
第1遍合并结果:
(4)重复两两合并,经过第2遍合并,得到长度为4的有序表序列,再将这些长度为4的有序表进行两两合并,如图所示。
第2遍合并结果:
(5)经过第3遍合并,得到长度为8的有序表序列,以及最后只有一个元素的序列,如图所示:
第3遍合并结果:
(6)将这两个序列进行合并,即可完成合并排序,最后的结果如图所示:
第四遍合并结果:
2.合并排序算法
代码如下:
/**
*
* @param arr 排序的数组
* @param left 左边有序序列的开始索引
* @param right 右边索引
* @param mid 中间索引
* @param temp 中转数组
*/
public static void merge(int[] arr,int left,int right,int mid,int[] temp){
//System.out.println("×××××");//合并的次数
int i = left;//初始化i,左边有序序列的初始索引
int j=mid+1;//初始化j,右边有序序列的初始索引
int t=0;//指向temp数组的当前索引
//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数组的元素copy到arr
//注意并不是每次都拷贝所有
t=0;
int tempLeft=left;//
//第一次合并时tempLeft=0,right=1 //tempLeft=2,right=3
// tempLeft=0,right=3 //tempLeft=0,right=7
//System.out.println("tempLeft="+tempLeft+"\t"+"right="+right);
while(tempLeft<=right){
arr[tempLeft]=temp[t];
t+=1;
tempLeft+=1;
}
}
我们还可以去测试它的运行效率,这里给出代码,大家自行检测:
package DataStructures.pro0925Sort;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
/**
* @Author DreamYee
* @Create 2019/11/16 17:15
*/
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];
System.out.println("归并排序前:"+ Arrays.toString(arr));
mergeSort(arr,0,arr.length-1,temp);
System.out.println("归并排序后:"+ Arrays.toString(arr));
/*
//创建要给80000个数据的数组
int[] arr=new int[800000];
int[] temp=new int[arr.length];//归并排序需要额外的空间
for(int i=0;i<800000;i++){
arr[i]=(int)(Math.random()*8000000);//生成一个[0,8000000)数
}
Date date1=new Date();
SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1Str=simpleDateFormat.format(date1);
System.out.println("排序前的时间:"+date1Str);
mergeSort(arr,0,arr.length-1,temp);
Date date2=new Date();
String date2Str=simpleDateFormat.format(date2);
System.out.println("排序后的时间:"+date2Str);
//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,right,mid,temp);
}
}
//合并的方法
/**
*
* @param arr 排序的数组
* @param left 左边有序序列的开始索引
* @param right 右边索引
* @param mid 中间索引
* @param temp 中转数组
*/
public static void merge(int[] arr,int left,int right,int mid,int[] temp){
//System.out.println("×××××");//合并的次数
int i = left;//初始化i,左边有序序列的初始索引
int j=mid+1;//初始化j,右边有序序列的初始索引
int t=0;//指向temp数组的当前索引
//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数组的元素copy到arr
//注意并不是每次都拷贝所有
t=0;
int tempLeft=left;//
//第一次合并时tempLeft=0,right=1 //tempLeft=2,right=3
// tempLeft=0,right=3 //tempLeft=0,right=7
//System.out.println("tempLeft="+tempLeft+"\t"+"right="+right);
while(tempLeft<=right){
arr[tempLeft]=temp[t];
t+=1;
tempLeft+=1;
}
}
}
好啦,归并排序就说到这,大家有什么可以留言哦