2010年6月20日日曜日

順列生成

順列を生成.

再帰による辞書式順でない順列生成
  1. public void generate(int[] a){  
  2.  recursive(a,0);  
  3. }  
  4.   
  5. private void recursive(int[] a,int j){  
  6.  if(j==a.length){  
  7.   System.out.println(Arrays.toString(a));  
  8.   return;  
  9.  }  
  10.  for(int i=j;i<a.length;i++){  
  11.   // a[i]とa[j]を入れ替え  
  12.   int t=a[j]; a[j]=a[i]; a[i]=t;  
  13.   recursive(a,j+1);  
  14.   // a[i]とa[j]を入れ替え  
  15.   t=a[j]; a[j]=a[i]; a[i]=t;  
  16.  }  
  17. }  

再帰による辞書式順順列生成
  1. public void generate(int[] a){  
  2.  recursive(a,0);  
  3. }  
  4.   
  5. private void recursive(int[] a,int j){  
  6.  if(j==a.length){  
  7.   System.out.println(Arrays.toString(a));  
  8.   return;  
  9.  }  
  10.  for(int i=j;i<a.length;i++){  
  11.   // j~iを循環右ローテート  
  12.   int t=a[i];  
  13.   for(int k=i;k>j;k--)  
  14.    a[k]=a[k-1];  
  15.   a[j]=t;  
  16.   recursive(a,j+1);  
  17.   // j~iを循環左ローテート  
  18.   for(int k=j;k<i;k++)  
  19.    a[k]=a[k+1];  
  20.   a[i]=t;  
  21.  }  
  22. }  

辞書式順でない順列生成では,単純に2つの要素を交換していますが,辞書式順の順列生成では,その操作を右ローテートに置き換えています.
右ローテートだと辞書式順になる理由は以下の通り.

a1a2…an
と要素が並んでいて,
ai>ai+1
とします.(色々説明が面倒なので要素aiを数とします)
aiを先頭に置いた時,辞書式順で初めに来る列(=最小値)は何かというと,
a1…ai-1aiai+1…an
のaiを先頭に持ってきた
ai[a1…ai-1ai+1…an]
になります.ちょうどこれは,元の列のa1…aiを右にローテートしたものです.
というわけで,i=1~nについてこの操作を実行すると,
a1[a2a3…an-1an]
a2[a1a3…an-1an]

an-1[a1a2…an-2an]
an[a1a2…an-2an-1]
とn個の列が出来ます.
それぞれの列について再帰させ,[]内でも同様の操作を行うと,1つの列あたりn-1個の列が出来ます.

a1[a2[a3a4…an-1an]]
a1[a3[a2a4…an-1an]]

a1[an-1[a2a3…an-2an]]
a1[an[a2a3…an-2an-1]]

[[]]の一番内側の列は,2項目までを決定した時の最小値です.
というわけで,n回再帰することで,辞書式順の順列が作れます.

0 件のコメント: