2016-07-27 16 views
1

Ich versuche, einen VBA-Code zu machen, um k-Element-Teilmenge eines N-Set in einer Sequenz zu ordnen. Mit anderen Worten, ich versuche, alle von k-permutations of n Mitgliedssatz aufzulisten. Zum Beispiel versuchen wir, alle 2-permutations of set {A,B,C} aufzulisten, wobei sich jedes Zeichen in den Zellen Range("A1:C1") befindet. Hier sind alle Permutationen:Array-Version von partiellen Permutation Generator in VBA Excel

{A,B}  {A,C}  {B,A}  {B,C}  {C,A}  {C,B} 

Der folgende Code die obige Aufgabe gut funktioniert zu implementieren, wenn es in den einzelnen Zeichen der Dateneingabe kein Duplikat ist:

Sub Permutation() 
Dim Data_Input As Variant, Permutation_Output As Variant 
Dim Output_Row As Long, Last_Column As Long 

Rows("2:" & Rows.Count).Clear 
Last_Column = Cells(1, Columns.Count).End(xlToLeft).Column 
Data_Input = Application.Transpose(Application.Transpose(Range("A1", Cells(1, Last_Column)))) 

k = InputBox("Input the value of k for P(" _ 
    & UBound(Data_Input) & " , k) where k is an integer between 2 and " _ 
    & UBound(Data_Input) & " inclusive.", "Permutation", 1) 

If k >= 2 And k <= UBound(Data_Input) Then 
    Output_Row = 2 
    ReDim Permutation_Output(1 To k) 
    Call Permutation_Generator(Data_Input, Permutation_Output, Output_Row, 1) 
Else 
    MsgBox "The input [" & k & "] is invalid. The input must be an integer between 2 and " _ 
    & UBound(Data_Input) & " inclusive." 
End If 

End Sub 

Function Permutation_Generator(Data_Input As Variant, Permutation_Output As Variant, _ 
           Output_Row As Long, Output_Index As Integer) 
Dim i As Long, j As Long, P As Boolean 

For i = 1 To UBound(Data_Input) 
    P = True 
    For j = 1 To Output_Index - 1 
     If Permutation_Output(j) = Data_Input(i) Then 
      P = False 
      Exit For 
     End If 
    Next j 
    If P Then 
     Permutation_Output(Output_Index) = Data_Input(i) 
     If Output_Index = k Then 
      Output_Row = Output_Row + 1 
      Range("A" & Output_Row).Resize(, k) = Permutation_Output 
     Else 
      Call Permutation_Generator(Data_Input, Permutation_Output, Output_Row, Output_Index + 1) 
     End If 
    End If 
Next i 
End Function 

Obwohl der obige Code nicht perfekt funktioniert gut für die Verarbeitung der doppelten Daten, aber ich versuche, seine Leistung zu verbessern, indem Sie die Eingabedaten setzen und alle k-Permutationen in Arrays finden. Hier ist der Code in der Array-Version:

Option Explicit 
Public k As Variant, Permutation_Table As Variant 
Sub Permutation() 
Dim Data_Input, Permutation_Output 
Dim Output_Row As Long, Last_Column As Long 

Rows("2:" & Rows.Count).Clear 
Last_Column = Cells(1, Columns.Count).End(xlToLeft).Column 
Data_Input = Application.Transpose(Application.Transpose(Range("A1", Cells(1, Last_Column)))) 

k = InputBox("Input the value of k for P(" _ 
    & UBound(Data_Input) & " , k) where k is an integer between 2 and " _ 
    & UBound(Data_Input) & " inclusive.", "Permutation", 1) 

ReDim Permutation_Table(1 To Output_Row - 2, 1 To k) 

If k >= 2 And k <= UBound(Data_Input) Then 
    Output_Row = 2 
    ReDim Permutation_Output(1 To k) 
    Call Permutation_Generator(Data_Input, Permutation_Output, Output_Row, 1) 
Else 
    MsgBox "The input [" & k & "] is invalid. The input must be an integer between 2 and " _ 
    & UBound(Data_Input) & " inclusive." 
End If 
Range("A3", Cells(Output_Row - 2, k)) = Permutation_Table 
End Sub 

Function Permutation_Generator(Data_Input As Variant, Permutation_Output As Variant, _ 
           Output_Row As Long, Output_Index As Integer) 
Dim i As Long, j As Long, n As Long, P As Boolean 

For i = 1 To UBound(Data_Input) 
    P = True 
    For j = 1 To Output_Index - 1 
     If Permutation_Output(j) = Data_Input(i) Then 
      P = False 
      Exit For 
     End If 
    Next j 
    If P Then 
     Permutation_Output(Output_Index) = Data_Input(i) 
     If Output_Index = k Then 
      Output_Row = Output_Row + 1 
      For n = 1 To k 
      Permutation_Table(Output_Row, n) = Permutation_Output(n) 
      Next n 
     Else 
      Call Permutation_Generator(Data_Input, Permutation_Output, Output_Row, Output_Index + 1) 
     End If 
    End If 
Next i 
End Function 

Leider stieß ich auf einige Fehler beim Versuch, es zu beheben. Der letzte Fehler, den ich festgestellt habe, ist der Laufzeitfehler '7'. Ich hoffe, dass jemand hier mir helfen könnte, es zu reparieren und zu verbessern, um einen guten Anagramm-Generator zu erzeugen, d. H. Es muss funktionieren können, wenn es doppelte Zeichen gibt. Zum Beispiel lassen Sie uns testen, um alle Zeichen in meinem Namen aufzulisten: ANA. The output sollte ANA, AAN und NAA sein, aber mein Code gibt nichts zurück. Für 2-permutations of my nameAN EIN,, AA mein Code gibt und NA noch sein sollte NA, AN und NA. Ich wäre ewig dankbar, wenn mir hier jemand helfen könnte.

Antwort

0

Schließlich fand ich den richtigen Code alle k-Permutationen unter Verwendung des Array-Verfahren zu erhalten sofern in dem Eingangs keine duplizierten Daten ist. Der folgende Code funktioniert gut und ziemlich schnell.

Dim k As Long, Permutation_Table 
Sub Permutation() 
Dim Data_Input, Permutation_Output 
Dim Output_Row As Long, Last_Column As Long, Array_Row As Long 

Rows("2:" & Rows.Count).Clear 
Last_Column = Cells(1, Columns.Count).End(xlToLeft).Column 
Data_Input = Application.Transpose(Application.Transpose(Range("A1", Cells(1, Last_Column)))) 

k = InputBox("Input the value of k for P(" _ 
    & UBound(Data_Input) & " , k) where k is an integer between 2 and " _ 
    & UBound(Data_Input) & " inclusive.", "Permutation", 1) 

Array_Row = WorksheetFunction.Fact(k) * WorksheetFunction.Combin(UBound(Data_Input), k) 

ReDim Permutation_Table(1 To Array_Row, 1 To k) 

If k >= 2 And k <= UBound(Data_Input) Then 
    ReDim Permutation_Output(1 To k) 
    Call Permutation_Generator(Data_Input, Permutation_Output, Output_Row, 1) 
Else 
    MsgBox "The input [" & k & "] is invalid. The input must be an integer between 2 and " _ 
    & UBound(Data_Input) & " inclusive." 
End If 
Range("A3").Resize(Array_Row, k) = Permutation_Table 'Use this line if UBound(Data_Input) < 10 
End Sub 

Function Permutation_Generator(Data_Input As Variant, Permutation_Output As Variant, _ 
           Output_Row As Long, Output_Index As Integer) 
Dim i As Long, j As Long, P As Boolean 

For i = 1 To UBound(Data_Input) 
    P = True 
    For j = 1 To Output_Index - 1 
     If Permutation_Output(j) = Data_Input(i) Then 
      P = False 
      Exit For 
     End If 
    Next j 
    If P Then 
     Permutation_Output(Output_Index) = Data_Input(i) 
     If Output_Index = k Then 
      Output_Row = Output_Row + 1 
      For n = 1 To k 
       Permutation_Table(Output_Row, n) = Permutation_Output(n) 
      Next n 
      Debug.Print Join(Permutation_Output, ",") 'Optional, use this line as the output if UBound(Data_Input) > 9 
     Else 
      Call Permutation_Generator(Data_Input, Permutation_Output, Output_Row, Output_Index + 1) 
     End If 
    End If 
Next i 
End Function 

P.S. Ich hoffe immer noch, dass hier jemand eine bessere Version, entweder eine kürzere oder eine schnellere Version, hat.