PAT 乙级 1035 插入与归并 Java 解决

写在最前:欢迎批评,欢迎任意地方的指正,用你们的优秀的java代码砸死我吧!!

问题——————

根据维基百科的定义:

插入排序是迭代算法,逐一获得输入数据,逐步产生有序的输出序列。每步迭代中,算法从输入序列中取出一元素,将之插入有序序列中正确的位置。如此迭代直到全部元素有序。

归并排序进行如下迭代操作:首先将原始序列看成 N 个只包含 1 个元素的有序子序列,然后每次迭代归并两个相邻的有序子序列,直到最后只剩下 1 个有序的序列。

现给定原始序列和由某排序算法产生的中间序列,请你判断该算法究竟是哪种排序算法?

输入格式:

输入在第一行给出正整数 N (≤100);随后一行给出原始序列的 N 个整数;最后一行给出由某排序算法产生的中间序列。这里假设排序的目标序列是升序。数字间以空格分隔。

输出格式:

首先在第 1 行中输出Insertion Sort表示插入排序、或Merge Sort表示归并排序;然后在第 2 行中输出用该排序算法再迭代一轮的结果序列。题目保证每组测试的结果是唯一的。数字间以空格分隔,且行首尾不得有多余空格。

输入样例 1:

10
3 1 2 8 7 5 9 4 6 0
1 2 3 7 8 5 9 4 6 0

输出样例 1:

Insertion Sort
1 2 3 5 7 8 9 4 6 0

输入样例 2:

10
3 1 2 8 7 5 9 4 0 6
1 3 2 8 5 7 4 9 0 6

输出样例 2:

Merge Sort
1 2 3 8 4 5 7 9 0 6

 解题思路:

首先这道题是关于插入排序和归并排序的过程的,这两个排序的过程需要根据题中所给出的顺序进行,否则就是错误,可是他题中给出的归并排序方法并不是大多数二路归并的做法,大多数二路归并的做法是二分递归,每次函数调用的时候分开递归处理前半部分和后半部分,所以排序一般是一半一半地排,不会出现他题中所给的一对一对地排的序列,只有重新写一种能符合他的归并方法的“伪递归”排序算法,为什么说是伪递归呢,因为我写的这个归并排序其实是循环的递归化,并不符合真正的处理小问题的传统递归思想,并且没有基准情况,推进动作也是不伦不类,甚至为了停止递归还增加了递归层数限制这个东西,所以,这道题说实话我是做的挺失败的,虽然拿到了满分。不过这道题可以帮人复习两种排序方法(虽然java排序用不到)。

代码极长,因为放了很多无用的东西,当时为了学习就把各种不同写法的归并排序和插入排序都存了起来,仅供参考。

package not.die.in.here;
//全对通过 ,得分25
import java.util.Scanner;


public class _1035_InsertMerge {
	static int flag = 0;
	static int[] print ;
	//数组一致性判断
	public static boolean check(int[] a,int[] b) {
		for(int i=0;i<a.length;i++) {
			if(a[i] != b[i])
				return false;
		}
		return true;
		
	}
	
	
//插入排序1  递归
	public static void insert(int[] a,int[] b,int start,int end,int length) {
		if(end < length) {
			//是否找完
			int index = end; //从后往前找
			int temp = 0;
			//查找最后一个元素应该插入到哪个位置,找到则退出循环
			for(int i=start;i<end;i++) {
				  if (a[end] < a[i]) {
		                index = i;
		                temp = a[end];
		                //找到位置后记住位置和需要挪动的数据
		                break;
		            }
			}
			//如果找到指定位置,则指定位置元素开始集体向后挪动一个单位,否则不变
			if(index != end) {
				for(int i = end-1;i>index-1;i--) {
					a[i+1] = a[i];
				}a[index] = temp;
			}
			end++;
			
			
			if(flag == 1) {
				System.out.println("Insertion Sort");
				for(int i=0;i<a.length;i++) {
					if(i<a.length-1)
						System.out.print(a[i] + " ");
					else
						System.out.print(a[i]);
				}
				flag=0;
				return;
			}
				
			//与b串对比验证
			if(check(a,b))
				flag = 1;
			insert(a,b,start, end, length);
		}
	}
	
	//插入排序2  非递归 从前往后
	//从第二个元素开始,每个元素只找他前面的,保证这个数一定比前面的大,
	public static void insertSort(int[] a){
	    int i, j;
	    int n = a.length;
	    int target;
	    //假定第一个元素被放到了正确的位置上
	    //这样,仅需遍历1 - n-1
	    for (i = 1; i < n; i++)
	    {
	        j = i;
	        target = a[i];
	        
	        while (j > 0 && target < a[j - 1])
	        {//每比较一次就和前面的元素换一个位置
	            a[j] = a[j - 1];
	            j--;
	        }
	        a[j] = target;
	        //与b串对比验证
			for(int k=0;k<a.length;k++) {
				System.out.print(a[k] + " ");
			}
			System.out.println();
	    } 
	}
	
	//题意归并排序
	//根据题意自制
	public static void mergeSort(int[][] a,int[] b) {
		int times = 0;//递归最大次数
		
		for(int i=1;i<a.length;i*=2)
			times++;//求次数
		
		int k = 0;//赋值次数
		//判断迭代次数是否正确即是否为最后一次
		if(times>0) {
			for(int i=0,j=0;i<a.length;i+=2,j++) {
				//System.out.println("i="+i+" j="+j);
				if(i<a.length-1) {//判断是否能够两个合成一个
					a[j] = mergeArray1(a[i], a[i+1]);
				}
				else {//不可以合成的话直接赋值
					a[j] = a[i];
				}
				//每次赋值完成都代表多添加一行
					k++;
			}
			int[][] temp=  new int[k][];
			for(int i=0;i<temp.length;i++) {
				//添加完以后截断源数组;改由新数组存储
				temp[i] = a[i];
			}
			
			
			//输出本次迭代完毕后的数列
			
				for(int i=0,p=0;i<temp.length;i++) {
					for(int j=0;j<temp[i].length;j++,p++) {
						print[p] = temp[i][j];
					}		
				}
				
			if(flag == 1) {
				System.out.println("Merge Sort");
				for(int i=0;i<print.length;i++) {
					if(i<print.length-1)
						System.out.print(print[i] + " ");
					else
						System.out.print(print[i]);
			}
			System.out.println();
			flag=0;
			return;
			}
			if(check(print,b))
				flag = 1;

			//迭代进行下次数列组合
			mergeSort(temp,b);
		}
	}
	
	//归并排序任意长度的数组
	public static int[] mergeArray(int[] a,int[] b){
		//temp存放结果
		int[] temp = new int[a.length + b.length];
		//temp插入的次数
		int k=0;
		int k1 = 0;
		temp[0] = a[0];
		k++;
		
		for(int i=1;i<a.length;i++) {
			//放a
			k1 = k;
			for(int j = 0;j<temp.length;j++) {
				if(temp[j] > a[i]) {
					//后挪一位
					System.arraycopy(temp,j,temp,j+1,temp.length-j-1);
					temp[j] = a[i];
					k++;
					break;
				}
			}
			if(k1 == k) {
				temp[k] = a[i];
				k++;
			}
		}
		
		for(int i=0;i<b.length;i++) {
			//放b
			k1 = k;
			for(int j = 0;j<temp.length;j++) {
				if(temp[j] > b[i]) {
					//后挪一位
					System.arraycopy(temp,j,temp,j+1,temp.length-j-1);
					temp[j] = b[i];
					k++;
					break;
				}
			}
			if(k1 == k) {
				temp[k] = b[i];
				k++;
			}
		}
		return temp;
	}
	//归并排序任意长度的两个数组改进
	public static int[] mergeArray1(int[] a,int[] b){
		//temp存放结果
		int[] temp = new int[a.length + b.length];
		int i = 0; //a的索引
		int j = 0; //b的索引
		int k = 0; //temp的索引
		while(i<a.length && j<b.length) {
			if(a[i] <= b[j]) {
				temp[k] = a[i];
				i++;k++;
			}else {
				temp[k] = b[j];
				j++;k++;
			}
		}
		while(i<a.length) {
			temp[k] = a[i];
			k++;i++;
		}
		while(j<b.length) {
			temp[k] = b[j];
			k++;j++;
		}
		return temp;
	}
	
	//普通归并排序,不符合题意
	public static void mergeSort(int[] array, int low, int high) {
		int mid = low+(high-low);
		if(high-low>1) 
			 mid = (int) (low + Math.sqrt(high - low)) ;	// mid = (high + low)/2的另一种算法,避免溢出
		if(high-low ==1)
			 mid = low;
		
		if(low < high) {
			mergeSort(array, low, mid);	  // 对array[low…mid]归并排序					
			mergeSort(array, mid+1, high);    // 对array[mid+1…high]归并排序			
			mergeArray(array, low, mid, high);// 融合
		}
		
		return;	
	}
	//普通归并迭代方法,不符合题意
	public static void mergeArray(int[] array, int low, int mid, int high) {
		int[] temp = new int[mid-low+1];	  //创建临时数组,只需要创建前一半即可
		for(int i = 0, j = low; i < temp.length; i++, j++) {
			temp[i] = array[j];		  //对临时数组进行赋值
		}
		int i = 0, j = mid+1, m = low;
		while(i < temp.length && j <= high) {     //将两个有序数组归并
			if(temp[i] <= array[j]) {	  //小于等于是为了维持稳定性
				array[m] = temp[i];
				i++; m++;
				continue;
			}
			else {
				array[m] = array[j];
				m++; j++;
				continue;
			}
		}
		while(i < temp.length)			  //最后将剩余的元素填充
			array[m++] = temp[i++];
		
		/*while(j <= high)
			array[m++] = array[j++];
			这一步其实可以不用做,因为此时array[j]==array[m]
		*/
		for(int r=low;r<=high;r++) {
			System.out.print(array[r]+" ");
		}
		System.out.println();
	}

	
	
	
	
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		int num = sc.nextInt();
		int[] a =  new int[num];
		int[] b = new int[num];
		int[][] aa= new int[num][1];
		for(int i=0;i<num;i++) {
			a[i] = sc.nextInt();
		}
		for(int i=0;i<num;i++) {
			b[i] = sc.nextInt();
		}
		sc.close();
		
		for(int i =0;i<num;i++) {
			aa[i][0] = a[i];
		}
		
		print = new int[num];
		
		insert(a,b,0,1,num);
		mergeSort(aa,b);
		
		

	}

}

提交截图:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值