递归实现
全排列的实现思路:
递归思路:n个数全排列相当于先抽取一个数做第一个数,再将剩下n-1个数全排列。所以实现方法是,枚举第一个数的情况,每次将剩下的数送进递归函数,直到剩下一个数。
排列思路:“枚举第一个数的情况”可以采用交换的方式。这步要实现的是把原本的第一个数放进“剩下的数”中。这“剩下的数”从序列第二位开始,顺序无意义,因此实现“删除一个数,再插入一个数”采用交换最方便。
伪代码:
permutation(序列a,序列总长度,“剩下的数”起始序号){
if(只有一个数)输出结果;return;
for(int i=起始序号;i<序列总长度,i++){
交换a[i]和a[起始序号];
permutation(a,序列总长度,起始序号+1);
把刚刚交换的换回去。
}
}
Java代码
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class TestClass {
static void swap(char[] a,int i,int j){
char tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
static void permutationByRecursion(char[] array,int length,int k){
if(k+1==length){
System.out.print(array);
System.out.print(" ");
return;
}
for(int i=k;i<length;i++){
swap(array,i,k);
permutationByRecursion(array,length,k+1);
swap(array,i,k);
}
}
public static void main(String[] args) throws FileNotFoundException {
Scanner sc=new Scanner(new File("list_testcase.txt"));
String tmp=sc.next();
int length=tmp.length();
char[] array=tmp.toCharArray();
permutationByRecursion(array,length,0);
}
}
用栈改写的非递归实现
用栈改写递归,首先要搞清楚栈和递归有什么关系。他们的关联在于,栈后进先出,递归也是后进入的函数先返回。那么这道题“最后进最先出”的是什么?是每一位都经过了交换的序列。
就以abc为例,看一下进出的过程:
水平翻转一下的话类似于后根序遍历的过程
箭头是递归返回的顺序,反过来就是入栈的顺序
那么按照入栈顺序就可以得到改写思路:初始序列(abc)入栈,初始序列(abc)出栈,多个子序列(a bc,b ac,c ba)入栈,一个子序列(cba)出栈,该子序列的所有子序列(c ba,c ab)入栈,如此循环往复。如果某代子序列已经排完则在出栈的同时打印结果。
如何记录已经交换到了第几位?(即递归写法中的k)没有想到什么巧妙的方法,就用了自己写的类似于c++的map类
伪代码:
Stack.push(map(Array,0));
while(top!=null){//循环直到栈空
tmp=Stack.pop();//弹出栈顶
k=tmp.second;
if(k+1==tmp.length)打印并continue;//已经排完了
for(k<=i<tmp.length){
交换tmp.first[ k ]和tmp.first[ i ];
Stack.push(tmp的拷贝,但second+1);//注意不能是tmp,因为传进去的是地址
再换回来;
}
}
Java代码:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
class MyMap{
char[] first;
int second;
public MyMap(char[]first,int second){
this.first=first.clone();
this.second=second;
}
}
public class TestClass {
static void swap(char[] a,int i,int j){
char tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
static void permutationByNoRecursion(char[] array){
MyStack stack=new MyStack();
stack.push(new MyMap(array,0));
while(stack.getTop()!=null){
MyMap tmp= (MyMap) stack.pop();
int k=tmp.second;
if(k+1==array.length){
System.out.print(tmp.first);
System.out.print(" ");
continue;
}
for(int i=k;i<array.length;i++){
swap(tmp.first,i,k);
stack.push(new MyMap(tmp.first, tmp.second+1));
swap(tmp.first,i,k);
}
}
}
public static void main(String[] args) throws FileNotFoundException {
Scanner sc=new Scanner(new File("list_testcase.txt"));
String tmp=sc.next();
int length=tmp.length();
char[] array=tmp.toCharArray();
permutationByNoRecursion(array);
}
}
补充:输出长度为 m 的字符串中取 n 个字符构成的所有全排列
static void permutationByRecursion(char[] array,int length,int k){
if(k+1==length){
System.out.print(array);
System.out.print(" ");
return;
}
// outer:
for(int i=k;i<length;i++){
// for (int j=k;j<i;j++){
// if(array[j]==array[i])continue outer;
// }
swap(array,i,k);
permutationByRecursion(array,length,k+1);
swap(array,i,k);
}
}
public static void main(String[] args) throws FileNotFoundException {
Scanner sc=new Scanner(new File("list_testcase.txt"));
String tmp=sc.next();
int length=tmp.length();
char[] array=tmp.toCharArray();
char[]res =new char[3];
Combination(array,res,length,3,0,0,3);
}