全排列迭代算法

看了网上基本是递归算法,当数据稍大一点就会炸了,13!=6227020800就已经超过4字节int类型最大值了,于是写一个全排列迭代算法。

全排列

全排列就是将数集按照一定的顺序排列起来
比如1,2,3的全排列为:
在这里插入图片描述

全排列的数量

n个数的全排列
1* 2* 3*…*(n-1)*n

即n的阶乘

全排列算法原理

对1,2,3,4,5进行全排列:
首先将数据排序

第一个排列:1,2,3,4,5
第二个排列:1,2,3,5,4
第三个排列:1,2,4,3,5
第四个排列:1,2,4,5,3
第五个排列:1,2,5,3,4
第六个排列:1,2,5,4,3
第七个排列:1,3,2,4,5

如果将1,2,3,4,5看成一个数——12345
那么每一个排列数都是在变大的,但是变化幅度不同

考虑增长规律:
如果最后一个数比前一个数大,他们两个较好就行了。
反之,他们两个是降序的,比如 1,2,4,5,3和1,2,5,4,3
出现降序子列意味着这个子列值最大,53比35大,543比345,354,435,453大
在子列中选一个比子列前面的数大1的数(一定有的,因为排序过,如果没有,则全排列完成),比如1,2,5,4,3,在3,4,5中选一个比2大1的数3,交换2,3,排列为
1,3,5,4,2
显然这样排列不利用后续工作,于是将原子列排序为1,3,2,4,5
重复一个增长过程,可得下一个排列为1,3,2,5,4

代码实现

考虑到阶乘函数增长的很快,减少排列对内存的占用,所以使用迭代过程
将每一个排列以数组提交
如果排列量太大,可以将计数升级为BigInteger
class Itr implements Iterator<int[]>{
	int[] root;
	int count=0;
	long title;
	int len;
	public Itr(int n) {
		root=new int[n] ;
		len=n;
		title=II(n);
		for(int i=0;i<root.length;i++) {
			root[i]=i;
		}
	}
	public boolean hasNext() {
		return count<title;
	}
	public int[] next() {
		plus();
		return root;
	}
	//迭代过程
	private void plus() {
		count++;
		if(count==1) {
			return;
		}
		//后面的大 较换
		if(root[len-2]<root[len-1]) {
			swap(len-2,len-1);
		}else {
			//后面的小
			int index=len-2;
			while(root[index]>root[index+1]) index--;
			int than=len-1;
			
			while(root[than]<root[index])than--;
			swap(index,than);
			Arrays.sort(root,index+1,len);
		}	
		
	}
	
	private void swap(int a,int b) {
		int tmp = root[a];
		root[a]=root[b];
		root[b]=tmp;
	}
	public long II(int n) {
		long value=1;
		while(n>1) {
			value*=n;
			n--;
		}
		return value;
	}
}

算法测试

    public static void show(int[] array) {
    	for(int out:array) {
    		System.out.print((out+1)+"\t");
    	}
    	System.out.println();
    }
    public static void main(String[] args) {
		Itr itr=new Itr(3);
		while(itr.hasNext()) {
			show(itr.next());
		}
	}

输出结果:
在这里插入图片描述

		Itr itr=new Itr(4);
		while(itr.hasNext()) {
			show(itr.next());
		}

在这里插入图片描述

将排列拼接为字符串存放于Set中,通过比对Set的数量进行检验

	public static void test(Itr itr) {
		Set<String> set=new HashSet<String>();
		while(itr.hasNext()) {
		//	System.out.println("next");
			int[] array = itr.next();
			String s="";
			for(int i=0;i<array.length;i++) {
				s+=array[i];
			}
			set.add(s);
		}
		System.out.println("set size"+set.size());
	}
	public static void main(String[] args) {
		test(new Itr(3));
		test(new Itr(4));
		test(new Itr(5));
		test(new Itr(6));
		test(new Itr(7));
	}

set size6
set size24
set size120
set size720
set size5040

3!=6
4!=24
5!=120
6!=720
7!=5040

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值