全排列的遞歸java
1. 全排列遞歸演算法
希望我的答復可以幫助你加深理解:
第一,perm函數中的條件for(int i=k;i<=m;i++)應更正為 for(int i=k;i<m;i++)
第二,你可以在核心步驟的前後列印有關變數的值,分析查看每一步的具體執行情況,這是編程調試的重要能力,要加強。
第三,以下是我提供的附件程序及運行結果(以1,2,3這個數組的全排列),可輔助分析:
1. 程序源碼=================================================
#include <stdio.h>
#include <stdlib.h>
int N,P=0;
void swap(int a[],int i,int j)
{
int temp=a[i];
a[i]=a[j];
a[j]=temp;
}
void perm(int a[],int k,int m,int pk,int pm)
{
int i;
/*k為中間變數,m初始化為參與排列元素的起始坐標和終止坐標
pk,pm分別表示參與排列元素的起始坐標和終止坐標,整個遞歸過程保持不變*/
if(k==m)
{
printf("----->perm %d :\n",P/N+1);/*列印提示*/
for(i=pk;i<pm;i++)
{
printf("%d ",a[i]);
P=P+1;
}
printf("\n\n");
}
else
{
for(i=k;i<m;i++)
{
printf("a %d,%d,%d,%d,%d\n",i,k,a[0],a[1],a[2]);
swap(a,k,i);
printf("b %d,%d,%d,%d,%d\n",i,k,a[0],a[1],a[2]);
perm(a,k+1,m,pk,pm);
printf("c %d,%d,%d,%d,%d\n",i,k,a[0],a[1],a[2]);
swap(a,k,i);
printf("d %d,%d,%d,%d,%d\n",i,k,a[0],a[1],a[2]);
}
}
}
int main()
{
/*調節以下N值及對應數組內容,可列印對應數組對應的全排列*/
N=3;
int t[]={1,2,3};
/*調節以上N值及對應數組內容,可列印對應數組對應的全排列*/
perm(t,0,N,0,N);
printf("----->Over!\n");/*列印提示*/
system("pause");
return 0;
}
2.列印結果 ============================================================
a 0,0,1,2,3
b 0,0,1,2,3
a 1,1,1,2,3
b 1,1,1,2,3
a 2,2,1,2,3
b 2,2,1,2,3
----->perm 1 :
1 2 3
c 2,2,1,2,3
d 2,2,1,2,3
c 1,1,1,2,3
d 1,1,1,2,3
a 2,1,1,2,3
b 2,1,1,3,2
a 2,2,1,3,2
b 2,2,1,3,2
----->perm 2 :
1 3 2
c 2,2,1,3,2
d 2,2,1,3,2
c 2,1,1,3,2
d 2,1,1,2,3
c 0,0,1,2,3
d 0,0,1,2,3
a 1,0,1,2,3
b 1,0,2,1,3
a 1,1,2,1,3
b 1,1,2,1,3
a 2,2,2,1,3
b 2,2,2,1,3
----->perm 3 :
2 1 3
c 2,2,2,1,3
d 2,2,2,1,3
c 1,1,2,1,3
d 1,1,2,1,3
a 2,1,2,1,3
b 2,1,2,3,1
a 2,2,2,3,1
b 2,2,2,3,1
----->perm 4 :
2 3 1
c 2,2,2,3,1
d 2,2,2,3,1
c 2,1,2,3,1
d 2,1,2,1,3
c 1,0,2,1,3
d 1,0,1,2,3
a 2,0,1,2,3
b 2,0,3,2,1
a 1,1,3,2,1
b 1,1,3,2,1
a 2,2,3,2,1
b 2,2,3,2,1
----->perm 5 :
3 2 1
c 2,2,3,2,1
d 2,2,3,2,1
c 1,1,3,2,1
d 1,1,3,2,1
a 2,1,3,2,1
b 2,1,3,1,2
a 2,2,3,1,2
b 2,2,3,1,2
----->perm 6 :
3 1 2
c 2,2,3,1,2
d 2,2,3,1,2
c 2,1,3,1,2
d 2,1,3,2,1
c 2,0,3,2,1
d 2,0,1,2,3
----->Over!
請按任意鍵繼續. . .
2. 全排列的遞歸
設(ri)perm(X)表示每一個全排列前加上前綴ri得到的排列.當n=1時,perm(R)=(r) 其中r是唯一的元素,這個就是出口條件.
當n>1時,perm(R)由(r1)perm(R1),(r2)perm(R2),...(rn)perm(Rn)構成. voidPerm(list[],intk,intm)//k表示前綴的位置,m是要排列的數目.{if(k==m-1)//前綴是最後一個位置,此時列印排列數.{for(inti=0;i<m;i++){printf(%d,list[i]);}printf(
);}else{for(inti=k;i<m;i++){//交換前綴,使之產生下一個前綴.Swap(list[k],list[i]);Perm(list,k+1,m);//將前綴換回來,繼續做上一個的前綴排列.Swap(list[k],list[i]);}}}//此處為引用,交換函數.函數調用多,故定義為內聯函數.inlinevoidSwap(int&a,int&b){inttemp=a;a=b;b=temp;}函數Perm(int list[],int k,int m)是求將list的第0~k-1個元素作為前綴、第k~m個元素進行全排列得到的全排列,如果k為0,且m為n,就可以求得一個數組中所有元素的全排列。
其想法是將第k個元素與後面的每個元素進行交換,求出其全排列。這種演算法比較節省空間。 n個數的排列可以從1.2....n開始,至n.n-1....2.1結束。
也就是按數值大小遞增的順序找出每一個排列。
以6個數的排列為例,其初始排列為123456,最後一個排列是654321,如果當前排列是124653,找它的下一個排列的方法是,從這個序列中從右至左找第一個左鄰小於右鄰的數,如果找不到,則所有排列求解完成,如果找得到則說明排列未完成。
本例中將找到46,計4所在的位置為i,找到後不能直接將46位置互換,而又要從右到左到第一個比4大的數,本例找到的數是5,其位置計為j,將i與j所在元素交換125643,然後將i+1至最後一個元素從小到大排序得到125346,這就是124653的下一個排列,如此下去,直至654321為止。演算法結束。 intb[N];intis_train(inta[],intn){inti,j,k=1;for(i=1;i<=n;i++){for(j=i+1;j<=n;j++)if(a[j]<a[i])b[k++]=a[j];/*判斷是否降序*/if(k>1)is_train(b,k);elsereturn(1);}}voidtrain(inta[],intn){inti,j,t,temp,count=1;t=1;printf(inputthe%3dthway:,count);for(i=1;i<=n;i++)printf(%3d,a[i]);printf(
);while(t){i=n;j=i-1;/*從右往左找,找第一個左鄰比右鄰小的位置*/while(j&&a[j]>a[i]){j--;i--;}if(j==0)t=0;elset=1;if(t){i=n;/*從右往左找,找第一個比front大的位置*/while(a[j]>a[i])i--;temp=a[j],a[j]=a[i],a[i]=temp;quicksort(a,j+1,N);/*調用快速排序*//*判斷是否符合調度要求*/if(is_train(a,N)==1){count++;printf(inputthe%3dthway:,count);for(i=1;i<=n;i++)printf(%3d,a[i]);printf(n);}}}}
3. java全排列 數組
全排列演算法很多,這是其中一個,使用遞歸——
import java.util.ArrayList;
import java.util.List;
public class PermAComb {
static List<int[]> allSorts = new ArrayList<int[]>();
public static void permutation(int[] nums, int start, int end) {
if (start == end) { // 當只要求對數組中一個數字進行全排列時,只要就按該數組輸出即可
int[] newNums = new int[nums.length]; // 為新的排列創建一個數組容器
for (int i=0; i<=end; i++) {
newNums[i] = nums[i];
}
allSorts.add(newNums); // 將新的排列組合存放起來
} else {
for (int i=start; i<=end; i++) {
int temp = nums[start]; // 交換數組第一個元素與後續的元素
nums[start] = nums[i];
nums[i] = temp;
permutation(nums, start + 1, end); // 後續元素遞歸全排列
nums[i] = nums[start]; // 將交換後的數組還原
nums[start] = temp;
}
}
}
public static void main(String[] args) {
int[] numArray = {1, 2, 3, 4, 5, 6};
permutation(numArray, 0, numArray.length - 1);
int[][] a = new int[allSorts.size()][]; // 你要的二維數組a
allSorts.toArray(a);
// 列印驗證
for (int i=0; i<a.length; i++) {
int[] nums = a[i];
for (int j=0; j<nums.length; j++) {
System.out.print(nums[j]);
}
System.out.println();
}
System.out.println(a.length);
}
}
4. Java數組的全排列,裡面布爾類型的數組vis[ ],在遞歸演算法里起了什麼作用,遞歸那塊理解不了,求詳細解答
不要急於看代碼,你心理要知道全排列的思路,不注重思路是很多程序員易犯的錯誤。
全排列演算法:
如果我求得固定第一位後的排列,那麼全部排列就可以求出,固定第一位有10種可能,可以循環求得。
如果我求得固定第二位後的排列,固定第一位後的排列就可以求出,固定第二位有9種可能,可以循環求得。
。。。
如果我求得固定第10位後的排列,固定第9位後的排列就可以求出,固定第10位有1種可能,可以循環求得。
這很明顯是遞歸的演算法。
static void dfs(int start,int end,int num){//為全部排列的集合,start為數字的位置,end為最後一位,num多餘的
if(start==end){//當前的數字位置為最後一位時,說明,一個序列已經生成
for(int i=1;i<end;i++)
System.out.print(a[i]+" ");//輸出序列
System.out.println();
}
else{//序列沒有生成時
for(int i=1;i<end;i++){
if(vis[i])//i是否在前面使用過
continue;//如果是直接跳過
a[start]=i;//確定start位置的數字,當start為1時就是確定第一位,有10種可能
vis[i]=true;//設置i為已使用狀態,避免下一位使用i
dfs(start+1,end,num);//求得確定start位後的全部序列
vis[i]=false;//設置i為未使用狀態
}
}
5. 關於各種排列組合java演算法實現方法
一 利用二進制狀態法求排列組合 此種方法比較容易懂 但是運行喊隱頌效率不高 小數據排列組合可以使用
復制代碼 代碼如下: import java util Arrays;//利用二進制演算法進行全排列 //count : //count :
public class test { public static void main(String[] args) { long start=System currentTimeMillis(); count (); long end=System currentTimeMillis(); System out println(end start); } private static void count (){ int[] num=new int []{ }; for(int i= ;i<Math pow( );i++){ String str=Integer toString(i ); int sz=str length(); for(int j= ;j< sz;j++){ str=" "+str; } char[] temp=str toCharArray(); Arrays sort(temp); String gl=new String(temp); if(!gl equals(" ")){ continue; } String result=""; for(int m= ;m<str length();m++){ result+=num[Integer parseInt(str charAt(m)+"")]; } System out println(result); } } public static void count (){ int[] num=new int []{ }; int[] ss=new int []{ }; int[] temp=new int[ ]; while(temp[ ]< ){ temp[temp length ]++; for(int i=temp length ;i> ;i ){ if(temp[i]== ){ temp[i]= ; temp[i ]++; } } int []tt=temp clone(); Arrays sort(tt); if(!Arrays equals(tt ss)){ continue; } String result=""; for(int i= ;i<num length;i++){ result+=num[temp[i]]; } System out println(result); } } }
二 用遞歸的思想攜慧來求排列跟組合 代碼量比較大
復制代碼 代碼如下鄭鄭: package practice;import java util ArrayList; import java util List;
public class Test {
/** * @param args */ public static void main(String[] args) { // TODO Auto generated method stub Object[] tmp={ }; // ArrayList<Object[]> rs=RandomC(tmp); ArrayList<Object[]> rs=cmn(tmp ); for(int i= ;i<rs size();i++) { // System out print(i+"="); for(int j= ;j<rs get(i) length;j++) { System out print(rs get(i)[j]+" "); } System out println(); } }
// 求一個數組的任意組合 static ArrayList<Object[]> RandomC(Object[] source) { ArrayList<Object[]> result=new ArrayList<Object[]>(); if(source length== ) { result add(source); } else { Object[] psource=new Object[source length ]; for(int i= ;i<psource length;i++) { psource[i]=source[i]; } result=RandomC(psource); int len=result size();//fn組合的長度 result add((new Object[]{source[source length ]})); for(int i= ;i<len;i++) { Object[] tmp=new Object[result get(i) length+ ]; for(int j= ;j<tmp length ;j++) { tmp[j]=result get(i)[j]; } tmp[tmp length ]=source[source length ]; result add(tmp); } } return result; } static ArrayList<Object[]> cmn(Object[] source int n) { ArrayList<Object[]> result=new ArrayList<Object[]>(); if(n== ) { for(int i= ;i<source length;i++) { result add(new Object[]{source[i]}); } } else if(source length==n) { result add(source); } else { Object[] psource=new Object[source length ]; for(int i= ;i<psource length;i++) { psource[i]=source[i]; } result=cmn(psource n); ArrayList<Object[]> tmp=cmn(psource n ); for(int i= ;i<tmp size();i++) { Object[] rs=new Object[n]; for(int j= ;j<n ;j++) { rs[j]=tmp get(i)[j]; } rs[n ]=source[source length ]; result add(rs); } } return result; }
}
三 利用動態規劃的思想求排列和組合
復制代碼 代碼如下: package Acm; //強大的求組合數 public class MainApp { public static void main(String[] args) { int[] num=new int[]{ }; String str=""; //求 個數的組合個數 // count( str num ); // 求 n個數的組合個數 count ( str num); }private static void count (int i String str int[] num) { if(i==num length){ System out println(str); return; } count (i+ str num); count (i+ str+num[i]+" " num); }
private static void count(int i String str int[] num int n) { if(n== ){ System out println(str); return; } if(i==num length){ return; } count(i+ str+num[i]+" " num n ); count(i+ str num n); } }
下面是求排列
復制代碼 代碼如下: lishixin/Article/program/Java/JSP/201311/20148
6. java中,用遞歸方法求n個數的無重復全排列,n=3。
程序如下所示,輸入格式為:
5
31212
第一行是數字個數,第二行有n個數,表示待排列的數,輸入假設待排序的數均為非負數。
importjava.io.File;
importjava.io.FileNotFoundException;
importjava.util.Arrays;
importjava.util.Scanner;
publicclassMain{
staticfinalintmaxn=1000;
intn;//數組元素個數
int[]a;//數組
boolean[]used;//遞歸過程中用到的輔助變數,used[i]表示第i個元素是否已使用
int[]cur;//保存當前的排列數
//遞歸列印無重復全排列,當前列印到第idx位
voidprint_comb(intidx){
if(idx==n){//idx==n時,表示可以將cur輸出
for(inti=0;i<n;++i){
if(i>0)System.out.print("");
System.out.print(cur[i]);
}
System.out.println();
}
intlast=-1;//因為要求無重復,所以last表示上一次搜索的值
for(inti=0;i<n;++i){
if(used[i])continue;
if(last==-1||a[i]!=last){//不重復且未使用才遞歸下去
last=a[i];
cur[idx]=a[i];
//回溯法
used[i]=true;
print_comb(idx+1);
used[i]=false;
}
}
}
publicvoidgo()throwsFileNotFoundException
{
Scannerin=newScanner(newFile("data.in"));
//讀取數據並排序
n=in.nextInt();
a=newint[n];
for(inti=0;i<n;++i)a[i]=in.nextInt();
Arrays.sort(a);
//初始化輔助變數並開始無重復全排列
cur=newint[n];
used=newboolean[n];
for(inti=0;i<n;++i)used[i]=false;
print_comb(0);
in.close();
}
publicstaticvoidmain(String[]args)throwsFileNotFoundException{
newMain().go();
}
}
客觀來說,非遞歸的無重復全排列比較簡單且高效。
7. 在java環境中用遞歸方法求n個數的無重復全排列,n=3。
給你個思路:
函數內判斷
if (元素個數==2){
列印結果:元素1,元素2;
列印結果:元素2,元素1;
} else {
列印結果:元素1,遞歸本函數(其他元素);
列印結果:遞歸本函數(其他元素),元素1;
}
8. java 輸入一個字元串,列印出該字元串中字元的所有排列
實現思路:就是輸入字元串後,通過遞歸的方式,循環每個位置和其他位置的字元。
importjava.util.Scanner;
publicclassDemo001{
public橋茄staticvoidmain(String[]args){
Stringstr="";
Scannerscan=newScanner(System.in);
str=scan.nextLine();
permutation(str.toCharArray(),0);
}
publicstaticvoidpermutation(char[]str,inti){
if(i>=str.length)
敏仿察return;
if(i==str.length-1){
System.out.println(String.valueOf(str));
}else{
for大芹(intj=i;j<str.length;j++){
chartemp=str[j];
str[j]=str[i];
str[i]=temp;
permutation(str,i+1);
temp=str[j];
str[j]=str[i];
str[i]=temp;
}
}
}
}