注意
- 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]);
}
}