字符集的排列算法(包括重排列)

问题:输入一串字符,每个字符都是唯一的,比如'a','b','c','d', 需要输出这串字符的全部排列。

分析:根据排列原理,排列的可能性有n!种(n为字符的个数)。直觉上讲,首先从字符集合中选取一个字符,然后从剩下的字符中选取另外一个字符,如 此下去,直到所有字符用完为止。另外一种可能性是:先假设一个子串已经排列好,比如abc,然后将下一个字符串d插入到已经排好的字符串的两边和中间位置 (这里共有4个位置)。下面实现的是第一种算法:

实现:

//chars: 输入的字符串
//used: 用于标记已经用过的字符
//pos: 当前处理的字符位置(从0到n-1)
//out: 输出的一个排列
public class CharPermutation {
        //字符串排序算法的一种实现
	public static void permute(char[] chars,boolean[] used,int pos,char[] out){
		if(pos==chars.length){
			System.out.println(out);			
			return;
		}
				
		for(int i=0;i<chars.length;i++){				
			if(!used[i]){
				out[pos] = chars[i];
				used[i] = true;
				permute(chars,used,pos+1,out);		
				used[i] = false;   //排列完毕,需要标记该字符可用
			}
		}
	}
	//测试部分
	public static void main(String[] args) {
		char[] chars = new char[]{'a','b','c','d'};
		boolean[] used = new boolean[]{false,false,false,false};
		char[] out = new char[4];
		permute(chars,used,0,out);
				
	}
}

上面程序中语句used[i] = false; 非常重要,递归调用完毕需要重新标记该字符可用。这样递归返回时可以在下一个for循环中再次使用该字符。例如如果当前循环的out为adb, 递归调用返回后字符c被标记为可用,这样下一次for循环可以使用c,即out的下一个值为adc。 如果有重复元素,以下是实现代码:

//Permutatation with repeated elements
public class CharPermutation {
    public static int COUNT;
	public static void permute(char[] chars,boolean[] used,int pos,char[] out){
		if(pos==chars.length){
			System.out.println(out);	
			COUNT++;
			
			return;
		}
				
		OUTER:
		for(int i=0;i<chars.length;i++){				
			if(!used[i]){
				for(int j=0;j<chars.length;j++){
					if(used[j]){
						//eliminate repeated elements by looking forward
						if(chars[i] == chars[j] && i<j){
							continue OUTER;
						}
					}
				}
				
				out[pos] = chars[i];
				used[i] = true;
				permute(chars,used,pos+1,out);		
				used[i] = false;  
			}
		}
	}
	
	public static void main(String[] args) {
		char[] chars = new char[]{'1','2','2','3','4','5'};		
		boolean[] used = new boolean[chars.length];	
		   
		char[] out = new char[chars.length];
		permute(chars,used,0,out);
		System.out.format("total permutations: %d%n",CharPermutation.COUNT);
	}
}

posted @ 2011-06-05 21:10  ljsspace  阅读(318)  评论(0编辑  收藏  举报