归并排序介绍
归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。
合并的细节:需要将两个已经有序的子序列合并成一个有序序列,比如上图中的最后一次合并,要将[4,5,7,8]和[1,2,3,6]两个已经有序的子序列,合并为最终序列[1,2,3,4,5,6,7,8],来看下实现步骤
代码思路
归并排序可分为两个部分:分组+合并。其中分组比较简单,分别对序列左边、右半部分递归分组即可。关键在于合并,下面是和并的思路:
1.定义两个指针,分别指向某个序列的首位和中间+1的位置,其实就是两个子序列的首位。
2.定义一个临时变量 temp,存放中间结果
2.两个子序列中的元素 >> temp
2.1 对比两指针所指元素的大小,挑出较小者送入temp,被挑走元素的序列的指针后移一位。
2.2 重复2.1的操作,直到某个子序列的指针移到其末尾。
3.现在只剩下某个序列的若干元素,它们是有序且较大的。再依次把他们送入temp即可。
4.移动完所有元素后再把temp的元素重新送回原始序列即可。
代码演示
//合并两个有序列表(形式上)为一个新列表
public static void Merge(Integer[] arr,Integer left,Integer mid,Integer right){
int i=left;//左半部分的指针
int j=mid+1;//右半部分的指针
Integer[] temp= new Integer[arr.length];
int index=0;//temp的索引,用于添加数据
//对比两个指针所指元素的大小,把小的存在temp中。直到有一个序列处理完
while(i<=mid && j<=right){
if(arr[i]<=arr[j]) temp[index++]=arr[i++];
else temp[index++]=arr[j++];
}
//要注意不一定两个指针同时到达各自序列的尾部,可能还剩某个序列的若干元素
//所以要把可能遗漏的元素加进temp
while(i<=mid){
temp[index++]=arr[i++];
}
while(j<=right){
temp[index++]=arr[j++];
}
//temp已经是排序后的arr了,完成任务,我们要把temp中的数据还给arr
index=0;
int k=left;
while(k<=right){
arr[k++]=temp[index++];
}
}
public static Integer[] MergeSort(Integer[] arr,Integer left,Integer right){
//不断分割,直到left=right,就是每组只有一个元素时停止
if(left<right){
//二路归并,每次把序列分成两个子序列
int mid=(left+right)/2;
MergeSort(arr,left,mid);
MergeSort(arr,mid+1,right);
Merge(arr,left,mid,right);
}
return arr;
}
@Test
public void testSort(){
Integer[] arr = init();
System.out.println("原始数据为:");
print(arr);
Long beginTime= System.currentTimeMillis();
Integer[] result = MergeSort(arr,0,arr.length-1);
Long endTime= System.currentTimeMillis();
System.out.println("排序结果为:");
print(result);
System.out.println("耗时:"+(endTime-beginTime)+" ms");
}
总结
归并=分组+合并,重点是合并!要注意这里的边界值实际上就是数组索引值,要遍历的到,所以合并过程中的循环操作都是带 ”=“ 的,忽略掉就会报错或者是错误的结果!惨痛的教训。