归并排序
小弟初来咋到,面对算法一脸懵逼,希望各位大神能够给予指点,在此谢过。
自上而下的归并排序
思路:化整为零,将一个大的序列分成两半分别排序,最后将结果按照顺序合并起来。
import java.util.Arrays;
/**
* Created by Fearless on 2017/3/27.
*/
public class Merge {
private static Comparable[] a={5,87,96,44,58,32};//测试数组
private static Comparable[] aux;//原数组的拷贝数组
/***
* 测试算法
* @param args
*/
public static void main(String ... args){
mergeSort(a);
System.out.println("S"+Arrays.toString(a));
}
public static void mergeSort(Comparable[] a){
int len=a.length;
aux=new Comparable[len];//实例化数组,设置大小为排序数组的大小
sort(a,0,(len-1));//进行排序,
}
/***
* 进行归并排序
* @param a 需要排序的数组
* @param i 排序起始位置索引
* @param i1 排序结束位置索引
*/
private static void sort(Comparable[] a, int i, int i1) {
if(i>=i1) return;//如果初始位置大于等于结束位置,不进行排序
int m=i+(i1-i)/2;//设置中间值;
sort(a,i,m);//对前半部分排序
sort(a,m+1,i1);//对后半部分进行排序
merge(a,i,m,i1);
/* System.out.println("sort "+i+" "+m);
System.out.println("sort "+(m+1)+" "+i1);
System.out.println("merge "+i+" "+i1+" "+Arrays.toString(a));*/
}
/***
* 合并两个相邻数组
* @param a 原数组
* @param i 前面数组的起始索引
* @param m 前面数组的结束索引
* @param i1 后面数组的结束索引
*/
private static void merge(Comparable[] a, int i, int m, int i1) {
//将要合并的数据全部放入aux中
for(int j=i;j<=i1;++j){
aux[j]=a[j];
}
//对数组进行遍历比较
int index1=i;
int index2=m+1;
for(int k=i;k<=i1;++k) {
//int t1=index1;
//int t2=index2;
if (index1 > m) {
//如果第一个数组已经遍历结束,就把第二个数组的剩余数据跟在后面
a[k]=aux[index2++];
}else if(index2>i1){
//如果第二个数组的数据已经遍历结束,就把第一个数组的剩余数据跟在后面
a[k]=aux[index1++];
}else if(less(aux[index1],aux[index2])){
//如果a[index1]比a[index2]小,(如果做升序排序就取小的)
a[k]=aux[index1++];
}else{
//如果a[index1]大于等于a[index2],(如果做升序排序就取小的)
a[k]=aux[index2++];
}
//if(i==0 && i1==9)
//System.out.println("add "+t1+" "+t2+" "+k+" \naux="+Arrays.toString(aux)+"\na="+Arrays.toString(a));
}
}
//a是否小于b
private static boolean less(Comparable a, Comparable b) {
return a.compareTo(b)<0;
}
}
自下而上的归并排序
思路:循序渐进,先两两比较,完后再将比较的结果按照顺序合并起来。
import java.util.Arrays;
/**
* Created by Fearless on 2017/3/28.
*/
public class MergeBU {
private static Comparable[] aux;//辅助数组
private static Comparable[] a={5,87,96,44,58,32,25,1,77,69,36,44};//测试数组
/***
* 测试
* @param args
*/
public static void main(String ... args){
sort(a);
System.out.println(Arrays.toString(a));
}
/***
* 排序算法
* @param a
*/
public static void sort(Comparable[] a){
int len=a.length;
aux=new Comparable[len];
/*arrLen:需要归并的数组大小,初始大小为1,因为每次归并都是合并两个相邻数组,
所以合并后大小比原大小扩大一倍*/
for(int arrLen=1;arrLen<len;arrLen=arrLen*2){
/*index1为归并的第一个数组的索引,因为一次是要归并两个数组,
所以在一次归并结束后要跳过归并的两个数组的索引
*/
for(int index1=0;index1<len-arrLen;index1+=arrLen*2){
/*
* index1+arrLen*2-1 为理论上第二个数组的最后一个数据的索引,
* 但是很多情况下的数组长度不是2^n 所以最后一个数组的索引应该按照实际的长度来计算
* 这样就需要对理论长度和实际长度做取最小操作,防止数组越界
* */
merge(a,index1,index1+arrLen-1,Math.min(index1+arrLen*2-1,len-1));
}
}
}
/***
* 合并两个相邻数组
* @param a 原数组
* @param i 前面数组的起始索引
* @param m 前面数组的结束索引
* @param i1 后面数组的结束索引
*/
private static void merge(Comparable[] a, int i, int m, int i1) {
//将要合并的数据全部放入aux中
for(int j=i;j<=i1;++j){
aux[j]=a[j];
}
//对数组进行遍历比较
int index1=i;
int index2=m+1;
for(int k=i;k<=i1;++k) {
//int t1=index1;
//int t2=index2;
if (index1 > m) {
//如果第一个数组已经遍历结束,就把第二个数组的剩余数据跟在后面
a[k]=aux[index2++];
}else if(index2>i1){
//如果第二个数组的数据已经遍历结束,就把第一个数组的剩余数据跟在后面
a[k]=aux[index1++];
}else if(less(aux[index1],aux[index2])){
//如果a[index1]比a[index2]小,(如果做升序排序就取小的)
a[k]=aux[index1++];
}else{
//如果a[index1]大于等于a[index2],(如果做升序排序就取小的)
a[k]=aux[index2++];
}
//if(i==0 && i1==9)
//System.out.println("add "+t1+" "+t2+" "+k+" \naux="+Arrays.toString(aux)+"\na="+Arrays.toString(a));
}
}
//a是否小于b
private static boolean less(Comparable a, Comparable b) {
return a.compareTo(b)<0;
}
}
PS:CSDN 的markdown画图没有有道云笔记的舒服啊,是我不会用吗?