看了网上基本是递归算法,当数据稍大一点就会炸了,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