归并排序
思路:依照分治模式
分解:将n个元素分成各含n/2个元素的子序列;
解决:对两个子序列递归地排序
合并:合并两个已排序的序列的子序列以得到排序结果
和快排区别:
归并的分解较为随意,重点是合并
对下列数组元素进行排序
两边数组各自进行排序
特殊情况当出现右区间数组元素个数比左区间元素个数多时,可以不用管
还有一种特殊情况当出现左区间数组元素个数比右区间元素个数多时
伪代码
MergerSort
mergeSort(A,p,r){ //数组A,左指针p,右指针r
if(p<r){ //左指针指的元素小于右指针指的元素
mid=p+((r-p)>>1); //找中间值
mergeSort(A,p,mid); //左区间
mergeSort(A,mid+1,r); //右区间
merge(A,p,mid,r); //整个数组
}
}
helper=[A.length]; //开辟一个和原数组长度相同的辅助区间
merge(A,p,mid,r){
copy(A,p,helper,p,r-p+1){ //先把A中的数据拷贝到helper中
left=p //左侧队伍的头部指针,指向待比较的元素
right=mid+1 //右侧队伍的头部指针,指向待比较元素
current=p //原数组的指针,指向待填入数据的
while(left<=mid&&right<=r){ //左边走的块,已经到头
if(helper[left]<=helper[right]){
A[current]=helper[left];
current++;
left++;
}
else{
A[current]=helper[right];
current++;
right++;
}
}
if(left<=mid){
A[current]=helper[left];
current++;
left++;
}
}
}
代码
package mergesort;
import com.sun.org.apache.xalan.internal.xsltc.compiler.util.Util;
public class Mergesort {
private static int[] helper; //开辟一个辅助空间
helper=new int[arr.length];
sort(arr,0,arr.length-1); //排序
}
//分成两段分别排序,然后再合并
private static void sort(int[] A,int p,int r) {
if(p<r) { //左指针小于右指针
int mid=p+((r-p)>>1); //求中间位置
sort(A,p,mid); //对左侧排序
sort(A,mid+1,r); //对右侧排序
merge(A,p,mid,r); //合并
}
}
//假设数组的两段分别有序,借助一个辅助数组来缓存原数组,用归并的思路将元素从辅助数组中拷贝原数组
//A原数组 p低位 mid中间位 r高位
private static void merge(int[] A,int p,int mid,int r) {
//拷贝到辅助空间的相同位置
System.arraycopy(A,p,helper,p,r-p+1);
int left=p,right=mid+1; //辅助数组的两个指针
//原始数组的 指针
int current=p; //当前指针指向
while(left<=mid&&right<=r) { //当左指针走的块已经到头
if(helper[left]<=helper[right]) { //辅助空间的左指针小于右指针
A[current++]=helper[left++]; //当前指针在左指针位置
}
else {
A[current++]=helper[right++];
}
}
//可能出现左边指针可能没有到头,右边的没有到头可以不管
while(left<=mid) {
A[current]=helper[left];
current++;
left++;
}
}
public static void main(String[] args) {
int[] arr=Util.getRandomArr(10,1,100); //测试指针
Util.print(arr);
sart(arr);
Util.println(arr);
Assertions.assertThat(Util.checkOrdered(arr,true)).isTrue();
}
}