在网上下载了一个实现各种算法的文档,其中有一个实现输出数字或者说元素所有排列顺序的程序。乍一看认为很简单但,于是想自己实现一下。但是试了试,比我想象的要困难。首先说明一下我要干什么:
比如:一组数字12,需要输出;12,21.
如果是1,2,3需要输出123
132
213
231
321
312
文档里提到了递归的思想, 于是就用递归的思想编一下。
用递归实现的过程实在是有些烦人,不知在何处递归,不知在何处打印。于是仔细的过了几遍程序和算法的实现过程。
第一步应该是第一个数依次和后边的换:
1234,2134,3213,4231
然后第二个和依次后边的换
1234 1234
1324
1432
2134 2134
2314
2431
3214 3214
3124
3412
4231 4231
4321
4132
然后第三个和第四个换:
1234 1234 1234
1243
1324 1324
1342
1432 1432
1423
2134 2134 2134
2143
2314 2314
2341
2431 2431
2413
3214 3214 3214
3241
3124 3124
3142
3412 3412
3421
4231 4231 4231
4213
4321 4321
4312
4132 4132
4123
在试了很多次递归不成功后,于是写了一个用for循环实现4个元素任意排列的(方便改成递归):
public class Pailie {
public static void main(String args[]){
int a[]={1,2,3,4};
for(int i=0;i<a.length;i++){
int temp=0;
temp=a[0];
a[0]=a[i];
a[i]=temp;
for(int i1=1;i1<a.length;i1++){temp=a[1];
a[1]=a[i1];
a[i1]=temp;
for(int i2=2;i2<a.length;i2++){temp=a[2];
a[2]=a[i2];
a[i2]=temp;for(int p=0;p<a.length;p++){System.out.print(a[p]);}System.out.println();temp=a[2];
a[2]=a[i2];
a[i2]=temp;}
temp=a[1];
a[1]=a[i1];
a[i1]=temp;}
temp=a[0];
a[0]=a[i];
a[i]=temp;
}}}
上边的是用最里层的循环打印,打印完之后,再复原到1234的状态。其中每一层循环都是获得需要的排列之后,然后再复原。经过分析以上的代码得到了下边可以获得所有排列的递归程序:
public class Pailie {
public void pl(int x,int y[]){
Pailie s1=new Pailie();
for(int i=x;i<y.length;i++){
int temp=0;
//这里实现按照传入的参数交换指定的两个元素
temp=y[x];
y[x]=y[i];
y[i]=temp;
//这个if条件可以看作是递归的出口
if(x<y.length-1){
//通过x的递增实现x元素的右移。
s1.pl(x+1, y);
//这个条件去除重复的打印(对应for循环的最内层打印)
if(x==y.length-2){for(int p=0;p<y.length;p++){System.out.print(y[p]);}System.out.println();}}
//还原
temp=y[x];y[x]=y[i];y[i]=temp;
}}
public static void main(String[] args) {
// TODO Auto-generated method stub
int a[]={1,2,3,4};
Pailie s=new Pailie();
s.pl(0, a);
}
}
上边的程序实现了对任意个元素的全排列,是严格按照上边说明的顺序及方法实现排列。需要说明的是这条程序可能在算法和执行上有可以简化的地方,但是易于理解。
下边贴一下,我在网找到的一段代码及其说明;
//排列组合
//说明:
//将一组数字、字母或符号进行排列,以得到不同的组合顺序,例如1 2 3这三个数的排列组合有:1 2 3、1 3 2、2 1 3、2 3 1、3 1 2、3 2 1。
//解法:
//可以使用递回将问题切割为较小的单元进行排列组合,例如1 2 3 4的排列可以分为1 [2 3 4]、2 [1 3 4]、3 [1 2 4]、4 [1 2 3]进行排列,这边利用旋转法,先将旋转间隔设为0,将最右边的数字旋转至最左边,并逐步增加旋转的间隔,例如:
//1 2 3 4 -> 旋转1 -> 继续将右边2 3 4进行递回处理
//2 1 3 4 -> 旋转1 2 变为 2 1-> 继续将右边1 3 4进行递回处理
//3 1 2 4 -> 旋转1 2 3变为 3 1 2 -> 继续将右边1 2 4进行递回处理
//4 1 2 3 -> 旋转1 2 3 4变为4 1 2 3 -> 继续将右边1 2 3进行递回处理
//
//实现:
//java实现
public class Permutation {
public static void perm(int[] num, int i) {
if(i < num.length - 1) {
for(int j = i; j <= num.length - 1; j++) {
int tmp = num[j];
// 旋转该区段最右边数字至最左边
for(int k = j; k > i; k--)
num[k] = num[k-1];
num[i] = tmp;
perm(num, i+1);
// 还原
for(int k = i; k < j; k++)
num[k] = num[k+1];
num[j] = tmp;
}
}
else {
// 显示此次排列
for(int j = 1; j <= num.length - 1; j++)
System.out.print(num[j] + " ");
System.out.println();
}
}
public static void main(String[] args) {
int[] num = new int[4+1];
for(int i = 1; i <= num.length - 1; i++)
num[i] = i;
perm(num, 1);
}
}
在网上搜了一下还有非递归的方法,当然是采用新的算法。搜一下全排列非递归实现就行了。上边粘来的代码是按照字典顺序输出的,相关信息请搜索。我的那段原创代码,可能有冗余的地方,但是我贴出了思考的过程易于理解。另外希望看到评论