归并排序有两种方式:采用递归的方式,从顶向下递归。采用非递归方式,两两归并,自底向上。
归并排序的核心都是归并操作:
1.申请空间,使其大小为两个已排序的数组大小之和,用来存放排序之后的数组。
2.复制数组,将数组a复制到辅助数组aux
2.分别指定已排序的两个数组头结点。
3.分别比较两个数组头元素,将较小值放入数组中。
4.重复3,直至全部排序完。
package Suanfa;
import Suanfa1;
public class Merge1 {
private static Comparable[] aux;
public static void merge(Comparable[] a,int lo,int mid,int hi) {
//Comparable[] aux=new Comparable[a.length];
//将两个已排序的数组[lo,mid]和[mid+1,hi]合并
int i=lo;//定义两个数组的头结点,之后不断的移动两个数组的头结点
int j=mid+1;
for (int k=lo;k<=hi;k++) {
aux[k]=a[k];
}
for (int l=lo;l<=hi;l++) {
if(i>mid) a[l]=aux[j++];
else if(j>hi) a[l]=aux[i++];
else if(Suanfa1.less(aux[j], aux[i])) a[l]=aux[j++];
else a[l]=aux[i++];
}
}
public static void sort(Comparable[] a) {
aux=new Comparable[a.length];
sort(a,0,a.length-1);
}
public static void sort(Comparable[] a, int lo, int hi) {
if(hi<=lo) return;//先写出递归基
int mid=lo+(hi-lo)/2;
//sort(a,lo,hi);
sort(a,lo,mid);
sort(a,mid+1,hi);
merge(a,lo,mid,hi);
}
public static void Msort(Comparable[] a) {
int N=a.length;
aux=new Comparable[a.length];
for (int sz=1;sz<N;sz*=2) {//1和1合并变为2
for (int lo=0;lo<N-sz;lo+=sz+sz) {
merge(a,lo,lo+sz-1,Math.min(lo+sz+sz-1, N-1));//防止最后一个节点超出范围
}
}
}
public static void main(String[] args) {
String[] a= {"B","D","A"};
//sort(a);
Msort(a);
Suanfa1.show(a);
}
}
归并排序的递归实现方法:
1.将一个数组的排序方式,变化为两个数组的合并方式。只要将两个数组都分别排好顺序了,之后再将两个数组合并那么最终的结果就是有序的。
2.利用一个辅助数组,aux,先将原有数组复制到aux中,然后每次将归并好的数组添加到原有数组中。给辅助数组定义两个指针,分别指向lo和mid+1,这样就可以将两个数组合并。
class paixu{
Comparable[] aux;
public static void sort(Comparable[] a){
aux=new Comparable[a.length];
sort(a,0,a.length-1);
}
public static void sort(Comparable[] a,int lo,int hi){
if(lo>=hi) return ;
int mid=lo+(hi-lo)/2;
sort(a,lo,mid);
sort(a,mid+1,hi);
merge(a,lo,mid,hi);
}
public static void merge(Comparable[] a,int lo,int mid,int hi){
//将两个已排序的数组合并[lo,mid] [mid+1,hi]合并为[lo,hi]
for(int i=lo;i<=hi;i++){
aux[i]=a[i];
}
int k=lo;
int j=mid+1;
for(int l=lo;l<=hi;l++){
if(j>mid) a[l]=aux[k++];
if(k>hi) a[l]=aux[j++];
if(aux[j]<aux[k]) a[l]=aux[j++];
else a[l]=aux[k++];
}
}
}
非递归实现方法:从底部向上,关键操作也是merge将一排需的数组合并。但是是从1 1合并为2,2 2合并为4,4 4合并为8
这里两个注意点:1.每次两两合并的大小都要翻倍,知道sz<len
2.对于每个sz都要从到到尾合并,关键是这里的每次合并头节点的增长,第一次lo=0,即将merge(a,0,sz-1,sz+sz-1)合并,第二次lo=sz+sz,....第三次lo=sz+sz+sz+sz+sz,即每次lo增长也是翻倍。
public static void Msort(Comparable[] a){
int len=a.length;
for(int sz=1;sz<len;sz*=2){//每次合并的大小都要不断翻倍
for(int lo=0;lo<len-sz;lo+=sz+sz){//为什么lo<len-sz,因为最后只要合并到前一个sz
//对于每个sz都要从头到尾都合并
merge(a,lo,lo+sz-1,Math.min(lo+sz+sz-1,len-1));
//注意这里中间节点是lo+sz-1,尾节点为了反正最后长度超过len-1,将尾尾节点定义为最小值
}
}
}