全排列的几种算法
全排列,我们高中时就学过,数学上很简单,可是用计算机的算法实现还是有点味道的,
今天我将我碰到的几种算法如数奉上,欢迎交流!
第一种:递归
最常见的也是最好理解的方法:
简单点:比如"a" ,"b","c"全排列,可以看做事"a" +"b","c"的全排列 及"b"+ "a","c"的全排列 及"c" + "a","b"的全排列
也就是说,遍历原数组中的每个元素,让剩余的元素全排列,这样就找到规律了。
代码如下:
public static void main(String[] args) { char buf[]={'a','b','c','d'}; perm(buf,0,buf.length-1); } public static void perm(char[] buf,int start,int end){ if(start==end){//当只要求对数组中一个字母进行全排列时,只要就按该数组输出即可(特殊情况) for(int i=0;i<=end;i++){ System.out.print(buf[i]); } System.out.println(); } else{//多个字母全排列(普遍情况) for(int i=start;i<=end;i++){//(让指针start分别指向每一个数) char temp=buf[start];//交换数组第一个元素与后续的元素 buf[start]=buf[i]; buf[i]=temp; perm(buf,start+1,end);//后续元素递归全排列 temp=buf[start];//将交换后的数组还原 buf[start]=buf[i]; buf[i]=temp; } } }
第二中方法:也是递归,
但是和第一种有所区别,
算法:将数据分为两部分,递归将数据从左侧移右侧实现全排列
比较抽象,
如list abcd,遍历每一个数,将每个数放到一个新的list中,并将该元素从原list删除,然后将剩下的元素继续遍历每个元素继续放到新的list里,这样,当list的长度为原list长度,或者原list长度为0时打印结果!
下面是简单的示意图:
// abcd //bcd a //cd ab //d abc //abcd //c abd //abdc //bd ac //d acb //acbd //b acd //acdb //bc ad ... //acd b ... //abd c ... //abc d ...
源代码如下:
private static void sort(List datas, List target) { //System.out.println("size="+datas.size()); if (datas.size()==0) { for (Object obj : target) System.out.print(obj+" "); System.out.print(" "); return; } for (int i = 0; i < datas.size(); i++) { List newDatas = new ArrayList(datas); List newTarget = new ArrayList(target); newTarget.add(newDatas.get(i)); newDatas.remove(i); sort(newDatas, newTarget); } } public static void main(String[] args) { List list = new ArrayList(); for(int i=0;i<5;i++){ list.add(i+1); } sort(list, new ArrayList()); }
第三种方法:非递归
直接上代码:
public static void main(String[] args) { int[] arr = new int[]{1,2,3,4,5,6}; for(int i :arr){ System.out.print(i + " "); } System.out.println(); int totalnum = 1; while(NextNumber(arr,arr.length)){ for(int i :arr){ System.out.print(i + " "); } System.out.println(); totalnum ++; } System.out.println("Total Num: " + totalnum); } private static Boolean NextNumber(int[] arr, int n){ //数组最后一个元素位置 int lastIndex = n-1; //从右向左确定第一个数字(前面的数字比它小) int firstIndex = lastIndex; for(;arr[firstIndex-1]>arr[firstIndex];firstIndex--){ if(firstIndex == 1){ //已经轮询完毕,此数已经是最大的那个数 return false; } } //从右向左确定一个交换数(此数比arr[firstIndex]小且比arr[firstIndex-1]大) int swapIndex = lastIndex; for(;swapIndex > firstIndex;swapIndex--){ if(arr[swapIndex] < arr[firstIndex] && arr[swapIndex] > arr[firstIndex-1]){ break; } } //交换数字 swap(arr,firstIndex-1,swapIndex); //将firstIndex右边的数字排序 for(;firstIndex < lastIndex;firstIndex++,lastIndex--){ if(arr[firstIndex] > arr[lastIndex]){ swap(arr,firstIndex,lastIndex); } } return true; } private static void swap(int[] arr,int i, int j){ int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; }
如果此文对你有帮助,请留个言,新人需要打架的支持和鼓励!