归并排序非递归Java实现(从例子分析,浅显易懂)

先举个非递归归并排序栗子吧!

例:将1,3,7,2,5,9,6排为升序(注:线内的为升序组)
第一趟归并后:1,3 ,2,7 ,5,9 ,6
第二趟归并后:1,2,3,7 ,5,6,9
第三趟归并后:1,2,3,7,5,6,9

一、我们来分析一下第二趟归并(分三步):

1.第二趟归并:从左至右【每相邻2个元素组成的】都是升序的,末尾可能存在一个【元素个数小于2的】升序
2.第二趟归并:从左至右每四个元素为一个单元,将每个单元内的两个升序通过merge函数合并为一个大的升序。最后剩余三个元素5,9和6,但这只是特例。令所有【四个元素组成的单元】内部归并后,剩余元素的个数为i,则0<=i<=3。我们不妨心里假设:没有剩余元素怎么办?剩余元素为5怎么办?剩余元素为5,9怎么办?剩余元素为5,9,6怎么办?

  • 没有剩余:无需操作。
  • 剩余为5:将5单独变为一组
  • 剩余为5,9:由于5,9为升序的,可以单独变为一组
  • 剩余为5,9,6:先将5,9和6归并为5,6,9,再单独变为一组

3.第二趟归并:从左至右【每相邻4个元素组成的】都是升序的,末尾可能存在一个【元素个数小于4的】升序

二、 发现递推

注意到【第二趟归并的描述】与【第二趟归并的描述】类似,可以循环递推。
循环递推最后得到:从左至右每相邻8个元素组成的组都是升序的,末尾可能存在一个元素个数小于8的升序组。即归并结束,整个组升序。

归纳

我们可以发现:第j趟归并后可以确定前2^j个元素为升序。
等效于:n个无序元素排成升序,需要⌈ log2(n) ⌉(向上取整) 趟归并。
又每趟归并时间复杂度为O(n),所以归并排序时间复杂度为O( n*log2(n) )。

不多BB看代码

下面是图片演示代码和测试数据,复制代码翻去最下面:

样例:
在这里插入图片描述
如果对你有帮助,点个攒呗!

import java.util.Scanner;

public class Main {
	//一、merge函数:将升序数组array[s,m]和array[m+1,e]合并为升序数组array[s,e]
	private static void merge(int[] array,int s,int m,int e) {
		int i=s,j=m+1,k=1;
		//i指向前面数组某元素,j指向后面数组某元素,k指向返回的result数组某元素
		int[] result=new int[e-s+2];
		while(i<=m&&j<=e) {
			if(array[i]<array[j]) {
				result[k]=array[i];
				i++;
			}else {
				result[k]=array[j];
				j++;
			}
			k++;
		}
		if(i>m) {//右边数组有剩余
			for(;j<=e;j++,k++) {
				result[k]=array[j];
			}
		}else {//左边数组有剩余的元素个数
			for(;i<=m;i++,k++) {
				result[k]=array[i];//
			}
		}
		//将result[1,k-1]的元素复制到array[s,e]
		for(k-=1;k>=1;k--) {
			array[k+(s-1)]=result[k];
		}
	}
	//二、主函数
	public static void main(String[] args) {
		Scanner scan = new Scanner(System.in);
		while (scan.hasNext()) {//!!输入多组数据!!!
			//1.输入
			int len=scan.nextInt();//先输入输入数组的长度
			int[] array=new int[len+1];
			for(int e=1;e<=len;e++) {//e为临时变量
				array[e]=scan.nextInt();
			}
			//2.快速排序
			for(int e=1;e<len;e*=2) {//e=1,2,4,8.....
				int start=1,middle=e,end=2*e;
				for(int i=1;i<=len/(2*e);i++){//标准合并len/(2*e)次
					merge(array,start,middle,end);
					start+=2*e;
					middle+=2*e;
					end+=2*e;
				}
				int rest=len-start+1;//标准合并后剩余元素个数为rest(0<=rest<=2*e-1)
				if(rest>e) {//(1)当e+1<=rest<=2*e-1,剩余元素不是有序的,合并为有序的
					merge(array,start,middle,len);
				}			//(2)当0<=rest<=e,残余元素是有序的,不需处理		
			}
			//3.输出
			for(int e=1;e<len;e++) {//e为临时变量
				System.out.print(array[e]+" ");
			}
			System.out.println(array[len]);//输出后换行
		}
		scan.close();
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值