【PTA】归并排序(指定归并次数)

目录

    • 题目来源
    • 问题描述
    • 思路分析
    • 算法实现

题目来源

作者: 姚军
单位: 重庆大学
时间限制: 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]两个子集,再分别对两个子集递归地调用自身。最终实现对整个数组的排序。
【PTA】归并排序(指定归并次数)_第1张图片

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++);
}
}

题目中的归并两次是指从下到上归并两层。然而,递归的归并排序运用在本题中却有点麻烦,因此从上向下的递归不好确定当前递归到的层数,当数据较多时容易出错。为此,我们可以考虑非递归的归并排序。
【PTA】归并排序(指定归并次数)_第2张图片

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的退出次数即可。

你可能感兴趣的:(PTA)