如果说递归是自上到下解决问题,那么非递归就是自下而上解决问题
归并的非递归思想是:
将原数组首先进行两个元素为一组进行排序,然后合并为四个一组进行排序,八个一组进行排序,直至合并整个数组;
如下图:
我们合并的序列分为左子序列与右子序列,假设每个序列的长度为s=2, i 的初始值为0,则如下图
//一次归并过程
private static void mergepass(int[] a, int[] b, int s) {
// TODO Auto-generated method stub
int i = 0;
// 如果数组的长度为偶数,将相邻的两个数值恰好能两两比较
while (i <= a.length - 2 * s) {// 右子序列的右边界i+2s-1<=a.length-1即i<=a.length-2s
mergeSort(a, b, i, i + s - 1, i + 2 * s - 1);
i = i + 2 * s;
}
//不为偶数时
if (i < a.length - s) {// 左子序列的右边界i+k-1<n,这个判断条件就保证了肯定存在右子序列,且剩余元素仍可分为两个子数组段,只不过第二个数组段不满。
mergeSort(a, b, i, i + s - 1, a.length - 1);
} else {// 剩余数组不满一个数组,直接合并到b里
for (int j = i; j < a.length; j++) {
b[i] = a[i];
}
}
}
全部代码为:
public static void main(String[] args) {
int a[] = new int[] { 49, 38, 65, 97, 76, 13, 27 };
merge(a);
System.out.println("排列好的数组:");
for (int c : a) {
System.out.print(c + " ");
}
}
private static void merge(int[] a) {
// TODO Auto-generated method stub
int[] b = new int[a.length];
int s = 1;
while (s < a.length) {
mergepass(a, b, s);// 先将排列好的数组赋值给中间数组b
mergepass(b, a, s);// 再将b的值赋给a
s += s;// 每次翻倍,1/2/4/8...
}
}
private static void mergepass(int[] a, int[] b, int s) {
// TODO Auto-generated method stub
int i = 0;
// 如果数组的长度为偶数,将相邻的两个数值恰好能两两比较
while (i <= a.length - 2 * s) {// 右子序列的右边界i+2s-1<=a.length-1即i<=a.length-2s
mergeSort(a, b, i, i + s - 1, i + 2 * s - 1);
i = i + 2 * s;
}
//不为偶数时
if (i < a.length - s) {// 左子序列的右边界i+k-1<n,这个判断条件就保证了肯定存在右子序列,且剩余元素仍可分为两个子数组段,只不过第二个数组段不满。
mergeSort(a, b, i, i + s - 1, a.length - 1);
} else {// 剩余数组不满一个数组,直接合并到b里
for (int j = i; j < a.length; j++) {
b[i] = a[i];
}
}
}
//归并排序
private static void mergeSort(int[] a, int[] b, int left, int mid, int right) {
int p1 = left, p2 = mid + 1, k = left;// p1,p2是检测指针,k是存放指针
while(p1<=mid&&p2<=right){
if (a[p1] < a[p2]) {
b[k++] = a[p1++];
} else {
b[k++] = a[p2++];
}
}
while(p1<=mid){// 如果第一个序列未检测完,直接将后面所有元素加到合并的序列中
b[k++] = a[p1++];
}
while (p2 <= right) {// 如果第二个序列未检测完,直接将后面所有元素加到合并的序列中
b[k++] = a[p2++];
}
for (int i = left; i <= right; i++) {
a[i] = b[i];
}