注意
- 1.在递归实现中,向下划分的过程中并没有实际操作。实际交换位置等merge操作是从底端向上进行的
- 2.因此递归过程可消除,避免不必要的系统开销
代码实现:
import java.util.Scanner;
public class 归并非递归实现 {
/**
* 归并排序(非递归)
* (合并内部已排好序的两两相邻数组)从切分的数组长度为1开始,一次归并变回原来长度的2倍
* @param nums 待排序数组
* @return 排好序的数组
*/
static int[] mergSort(int a[]) {
int len=1;
while(len<=a.length) {
//while终止条件
for(int i=0;i+len<a.length;i+=len*2) {
//for循环终止条件为当剩下的元素数量不超过一组时(即没有第二组与之合并了)
int lb=i,ub=i+len*2-1,mid=i+len-1;
if(ub>a.length-1) {
ub=a.length-1;//整个待排序数组为奇数的情况
}
merge(a,lb,mid,ub);
//其中[low,mid],[mid+1,high]为两组已排好序的数组,
//各自的长度为len;后者长度可能不满len,这只可能出现在原数组元素个数为奇时。
}
len*=2;
}
return a;
}
/**
* 将合并起来的两个内部已排序数组归并排序,同递归版,
* 先将左半部分存在L,右半部分存在R,然后直接对原数组进行修改。
* @param nums 带排序数组
* @param low 左边数组第一个元素索引
* @param mid 左边数组最后一个元素索引,mid + 1为右边数组第一个元素索引
* @param high 右边数组最后一个元素索引
*/
static void merge(int a[],int lb,int mid,int ub) {
int n1=mid-lb+1;
int n2=ub-mid;
int L[]=new int[n1+1];
int R[]=new int[n2+1];
for(int i=0;i<n1;i++) {
L[i]=a[lb+i];
}
for(int i=0;i<n2;i++) {
R[i]=a[mid+1+i];
}
L[n1]=R[n2]=Integer.MAX_VALUE;
int i=0,j=0;
for(int k=lb;k<=ub;k++) {
if(L[i]<=R[j]) {
a[k]=L[i];
i++;
}else {
a[k]=R[j];
j++;
}
}
}
public static void main(String args[]) {
Scanner sc=new Scanner(System.in);
int k=sc.nextInt();
int a[]=new int[k];
for(int i=0;i<k;i++) {
a[i]=sc.nextInt();
}
a = mergSort(a);
for(int i=0;i<k;i++) {
System.out.println(a[i]);
}
}