作者: 姚军
单位: 重庆大学
时间限制: 400 ms
内存限制: 64 MB
代码长度限制: 16 KB
请返回一个二路归并排序经过2次归并后的结果。
输入格式:
第一行是数据的总数n(<=10000)
第二行是对应的n个数据
输出格式:
输出两次归并后的结果。每个数据间以空格分隔,行末不可以有多余的空格。
输入样例:
8
12 2 51 4 9 1 20 7
输出样例:
2 4 12 51 1 7 9 20
首先回顾下一般归并排序的解法。如下图所示,递归的归并排序函数mergeSort将数据集分为[low mid]
,[mid+1,high]
两个子集,再分别对两个子集递归地调用自身。最终实现对整个数组的排序。
public static void mergeSort(int[] list,int low,int high)
{//递归法
int mid=(low+high)/2;
if (low < high)
{
mergeSort(list, low,mid);
mergeSort(list, mid+1,high);
merge(list, low, high);
}
}
public static void merge(int[] list,int low,int high){
ArrayList<Integer> temp = new ArrayList<Integer>();
int mid=(low+high)/2;
int i=low,j=mid+1,k=0;
while (i <=mid && j <= high)
{
if (list[i]<list[j])
{
temp.add(list[i++]);
}
else {
temp.add(list[j++]);
}
}
while (i<=mid)
{
temp.add(list[i++]);
}
while (j <= high) {
temp.add(list[j++]);
}
for (i=low;i<=high;i++)
{//[low,high]范围内的list替换
list[i]=temp.get(k++);
}
}
题目中的归并两次是指从下到上归并两层。然而,递归的归并排序运用在本题中却有点麻烦,因此从上向下的递归不好确定当前递归到的层数,当数据较多时容易出错。为此,我们可以考虑非递归的归并排序。
public static void mergeSort_nonRec(int[] list)
{//非递归法
//递归法是自顶向下划分,非递归法是自下向上划分
int size=1;
int low,mid,high;
while (size<=list.length-1)
{
low=0;
//表示当前递归结束的条件
while(low+size<=list.length-1)
{
mid=low+size-1;
high=mid+size;
if(high>list.length-1)
high=list.length-1;
merge(list, low, high);
//移动到下次递归的起始位置
low=high+1;
}
size*=2;
//不断扩大size
}
}
为了记录归并的次数,我们对非递归算法加以改进,加入count
变量。当count=2时,退出归并,返回结果。
public static void mergeSort_nonRec(int[] list)
{//非递归法
//递归法是自顶向下划分,非递归法是自下向上划分
int size=1;
int count=0;
int low,mid,high;
while (size<=list.length-1)
{
low=0;
//表示当前递归结束的条件
while(low+size<=list.length-1)
{
mid=low+size-1;
high=mid+size;
if(high>list.length-1)
high=list.length-1;
merge(list, low, high);
//移动到下次递归的起始位置
low=high+1;
}
size*=2;
//不断扩大size
count++;
if(count==2)
break;
}
}
同理,对于其他的归并次数,只要修改count的退出次数即可。