JAVA: alle Kombination gegebener Zeichen

  • #1
M

Michael_B

Bekanntes Mitglied
Themenersteller
Dabei seit
21.09.2002
Beiträge
860
Reaktionspunkte
0
Ort
Köln
Hiho...

ich kniffele gerade an einer Methode, die mir zu einem gegebenen Char-Array alle möglichen Kombinationen ausspuckt. Wenn also die Zeichen a, b und c gegeben sind, sollen die Kombinationen abc, acb, bac, bca, cab und cba ausgegeben werden. Jedes gegebene Zeichen darf auch nur einmal in einer Kombination erscheinen...
Klingt eigentlich ganz einfach aber irgendwie bin ich zu offenbar zu blöd dafür, nen vernünftigen Lösungsansatz zu finden...

Hat da jemand ne Idee?
THX in advance
M.
 
  • #2
Jo, das ist eigentlich ganz einfach:

Code:
n!

Wobei n die Anzahl der Elemente deines Array ist, also im Beispiel a, b, c n=3
 
  • #3
n! ist mir klar. Ich wollte aber nicht die Anzahl der möglichen Kombinationen, sondern die Kombinationen selbst. Z. B. auf Console ausgegeben.

Greetz
M.
 
  • #4
Oh, entschuldige. Da kann mal wieder einer nicht lesen. Ist schon spät ;D
Dann werde ich mir deines Problems bezüglich heute mal keine Gedanken mehr machen und das auf morgen verschieben, würde glaube ich eh nur Müll rauskommen ;D

Sorry.
 
  • #5
Macht nix. Dennoch danke... irgendwie komm ich auch nicht drauf... kann doch nicht so schwer sein. Frickele gerade an einer rek. Lösung. Ich glaube Rekursion ist bei diesem Problem absolut notwendig.

Ansatz:

Methode printCombos(String wort, Vector bs) //bs=buchstaben. wort ist beim allerersten Mal ein leerer String.

Methode macht nun für jeden Buchstaben im Vector folgendes {
schreibe den Buchstaben ins Wort
entferne den Buchstaben aus dem Vector. Jetzt sind nur noch alle anderen Buchstaben drin.
rufe printCombos auf mit dem Wort und dem neuen (reduzierten) Vector
}

Funktioniert aber nicht wirklich. :(
 
  • #6
Hi

Sollte so gehen:

possibilities(String[] arr, StringBuffer erg) {
if (arr.length == 0) {
sysout(erg.toString);
return;
}

for (int i = 0; i < arr.length;i++) {
possibilites(arr[ohne element i :)], erg.clone().append(arr));
}
}

Ist halt die Frage ob du das als Rückgabewerte oder nur auf stdout haben willst.

Gruß, Michael
 
  • #7
Hab das jetzt mal so umgesetzt:

Code:
public class BsKombo {

public static void possibilities(String[] arr, StringBuffer erg) {
  
  if (arr.length == 0) {
    System.out.println((erg.toString()));
    return;
  }
  
  for (int i = 0; i < arr.length;i++) {
    possibilites(arr, erg.clone().append(arr[i]));
  }

}


public static void main(String[] args) {

String[] urwort = new String[] {U, H, D, N};

possibilities(urwort, new StringBuffer());

}

}

Bekomme aber immernoch den Fehler, dass clone() protected access in java.lang.Object hat und irgendwie nicht mit StringBuffer erg verknüpft werden kann.

Greetz
M.
 
  • #8
Hi

Eine Sache ist noch falsch, du reduzierst das Problem bei der Rekursion nicht. Aus dem arr den du an die aufgerufene Funktion weitergibst muss das i Element raus, da dass ja benutzt wurde. Dafür kannst du dir ja eine eigene Funktion schreiben, war ich zu faul für :)

Wegen dem StringBuffer.clone() muss ich mal gucken. Ansonsten nimm String erg + arr, legt ja auch ein neues Objekt an.

Gruß, Michael
 
  • #9
Hi... hier mal deine Idee jetzt inkl. Reduktion des Arrays. Hab aus dem Array einen Vector gemacht, da man hier leichter ein Objekt rausschmeissen kann.

Code:
import java.util.*;
public class BsKombo {
   
   public static void possibilities(Vector arr, String erg) {
     
        if (arr.size() == 0) {
          System.out.println(erg);
          return;
        }
        
        Enumeration enu = arr.elements(); 
        
        while (enu.hasMoreElements()) {
          String tmp = (String)enu.nextElement();
          Vector t = new Vector(arr);
          arr.removeElement(tmp);
          possibilities(t, erg+tmp);
       }
   }
   
   
   public static void main(String[] args) {
      
      Vector urwort = new Vector();
     urwort.addElement(new String(a));
     urwort.addElement(new String(b));
      
      possibilities(urwort, );
      
   }
   
}

Jetzt bekomme ich folgende Exceptions beim Ausführen:
java.lang.StackOverflowError
at java.util.Vector.<init>(Vector.java:144)
at BsKombo.possibilities(BsKombo.java:15)
at BsKombo.possibilities(BsKombo.java:17)
at BsKombo.possibilities(BsKombo.java:17)
at BsKombo.possibilities(BsKombo.java:17)
at BsKombo.possibilities(BsKombo.java:17)
... (jede Menge davon)

Langsam bin ich mit meinem Latein am Ende....
 
  • #10
Hi

Das Problem müsste sein, dass der Vector beim remove nach dem originalen Stringobjekt sucht. Durch das auslesen wird aber glaube ein neues Objekt angelegt was nicht die gleiche Referenz hat. Alternativ könntest du eine Hashtable nehmen, der macht einen Stringvergleich.

Gruß, Michael
 
  • #11
Jo danke... habs jetzt angepasst, doch wieder mit nem String[]... es gibt auch keine Fehler...

Code:
import java.util.*;
public class BsKombo {
   
public static String[] reduceArray(String[] arr, String element) {

//wenn das element gar nicht im Array vorhanden ist, kann arr direkt zurückgegeben werden
if(Arrays.binarySearch(arr, element)<0) return arr;

String[] neu = new String[arr.length-1];//das neue Array
int x=0;//der Zähler für das neue Array
boolean schonreduziert = false;//Flag ob das Element schon entfernt wurde
//um sicher zu stellen, dass nur 1 Element rausgeschmissen wird

for (int i=0; i<arr.length; i++) {

if(!arr[i].equals(element) || schonreduziert) { 
//wir haben ein Element gefunden, das NICHT dem übergebenen gleicht
//bzw. es wurde schon ein Element aus dem Array geschmissen
neu[x++] = arr[i]; //also soll das Element ins neue Array gespeichert werden
}
else schonreduziert=true;

}

return neu;

}

 public static void possibilities(String[] arr, String erg) {
 
 if (arr.length == 0) {
 System.out.println(erg);
 return;
}

for (int i = 0; i < arr.length;i++) {
erg+=arr[i];
 possibilities(reduceArray(arr, arr[i]), new String(erg));
 }
}

public static void main(String[] args) {

String[] wort = new String[] {a, b, c};
String element=a;

Arrays.sort(wort); //wird gebraucht um später Arrays.binarySearch verwenden zu können

possibilities(wort, );
}
   
}

Allerdings arbeitet es nicht so, wie ich mir das vorgestellt habe... Hier mal der Output des Programms mit dem String[] {a, b, c}:
Code:
abc
abcb
abac
abaca
abcab
abcaba

Dort wo possibilities sich selbst wieder aufruft, wurde vorher einfach nur erg mit übergeben. Da hab ich gedacht, dass man da ein neues String-Objekt übergeben muss. Jetzt steht da halt new Sting(erg), aber das wars dann auch nicht.

Dennoch schonmal nen riesen Dank... ;)
Greetz
M.
 
  • #12
Hallo zusammen,

jetzt hat mich das Thema auch gereizt (welch passendes Wort ;D )

Hab das ganze mal als Excel-Makro geschrieben.
Eingabe wird in A1 des aktiven Blattes erwartet.
Ausgabe efolgt in Spalte B des aktiven Blattes.

Gruß Matjes :)

Code:
Option Explicit

Sub AlleVariationenEinerBuchstabenkombination()
 ->Alle Kombinationen der Character eines Strings erzeugen
 ->Input Zelle A1 des aktiven Blattes
 ->Output in Spalte B des aktiven Blattes
    
  Dim s_tmp As String, x As Long
 ->Kombinationen-Array und Zähler
  Dim Kombinationen() As String
  
 ->erstes Feld leer lassen
  ReDim Kombinationen(0 To 0)
  
 ->String holen
  s_tmp = ActiveSheet.Range(A1).Value
  If s_tmp =  Then
    MsgBox (kein String in A1 :-))
    Exit Sub
  End If
  
 ->maximale Kombinationsanzahl prüfen
 ->8 Zeichen sind bereits ca 40000 :-(
  If Len(s_tmp) > 8 Then
    MsgBox (maximal 8 Zeichen in A1 zulässig & vbLf & vbLf & _
            Anzahl Kombinationen > 65535)
    Exit Sub
  End If
  
 ->Kombinationen erzeugen
  Call Arbeitsbiene(Kombinationen(), , s_tmp)
  
 ->Ausgabe
  For x = 1 To UBound(Kombinationen)
    ActiveSheet.Cells(x, 2).Value = Kombinationen(x)
  Next
  
 ->Sortieren
  ActiveSheet.Range(ActiveSheet.Cells(1, 2), _
                    ActiveSheet.Cells(UBound(Kombinationen), 2)).Sort _
                    Key1:=ActiveSheet.Columns(2), _
                    Header:=xlNo
  
  
 ->doppelte Kombinationen löschen
  For x = UBound(Kombinationen) To 2 Step -1
    If ActiveSheet.Cells(x, 2).Value = _
       ActiveSheet.Cells(x - 1, 2).Value Then
      ActiveSheet.Cells(x - 1, 2).Delete Shift:=xlShiftUp
    End If
  Next
End Sub

Sub Arbeitsbiene(Kombinationen() As String, _
                 s_kombi As String, _
                 s_rest As String)
  Dim x As Long
  
  If Len(s_rest) = 1 Then
   ->Kombinationsfeld um 1 erweitern
    ReDim Preserve Kombinationen(0 To UBound(Kombinationen()) + 1)
   ->Kombination speichern
    Kombinationen(UBound(Kombinationen)) = s_kombi & s_rest
  Else
   ->für alle Buchstaben im Rest:
   ->eine Buchstaben aus Rest nehmen und an Kombination anfügen
   ->Rest entsprechend reduzieren
    For x = 1 To Len(s_rest)
      Call Arbeitsbiene(Kombinationen(), _
              s_kombi & Mid(s_rest, x, 1), _
              Left(s_rest, x - 1) & Right(s_rest, Len(s_rest) - x))
    Next
  End If
End Sub
 
  • #13
Danke. das ist sehr nett von dir... allerdings blick ich bei Makros net durch, da ich das noch nie, aber auch wirklich noch nie gemacht habe...

Greetz
M.
 
  • #14
Hallo Michael_B,

Dann beschreib ich das mal in normalen Worten
Unten siehst Du die eigentliche->Arbeitsbiene', also den rekursiven Teil des Programms.

Eingangsparameter sind:

a)der String s_kombi:
Hier gibt der Aufrufende die bisherige zusammengesuchte Kombination bekannt.
(beim ersten Aufruf der Arbeitsbiene ist er leer)

b)der String s_rest:
Hier gibt der Aufrufende bekannt was noch zu kombinieren ist
(beim ersten Aufruf der Arbeitsbiene enthält er den Ausgangs-String)

Bearbeitung:

a) Wenn der Rest s_rest nur noch ein Zeichen enthält ist die Kombination fertig.
Die Kombination setzt sich zusammen aus dem übergebene Kombinationsanfang und dem Rest (dem letzten Buchstaben).
Diese wird gespeichert und kein weiterer rekursiver Aufruf durchgeführt.

b) Der Rest enthält mehr als ein Zeichen
In einer Schleife wird die Arbeitsbiene aufgerufen. Als Aufrufparameter wird die erhaltene Kombination um ein Zeichen des erhalten Restes erweitert und als jeweils neue Kombination übergeben. Der erhaltene Rest wird um dieses Zeichen reduziert und als neuer Rest übergeben.

Also nicht die erhalten Parameter verändern ! Die braucht man in der Schleife beim nächsten Durchlauf.

Wenn man alle Kombinationen zusammen hat prüft man auf gleiche Kombinationen. Dies erfolgt im Hauptprogramm.

Ich hoffe dies hilft dir ein wenig.

Gruß Matjes :)
 
  • #15
Hi

So jetzt hab ich auch mal mein Java angeworfen, so funktioniert es:
Code:
   public static void possibilities(String[] arr, String erg) {
      
      if (arr.length == 0) {
         System.out.println(erg);
         return;
      }
      
      for (int i = 0; i < arr.length;i++) {
         possibilities(reduceArray(arr, arr[i]), erg + arr[i]);
      }
   }

Eine Erklärung dafür kann ich dir aber nicht geben :eek:

Gruß, Michael
 
  • #16
Das ist ja mal sehr suspekt... Der einzige Unterschied ist, dass ich in der for-Schleife von possibilities mit erg+=arr arbeite... Das kann ich aber ehrlich gesagt nicht nachvollziehen, warum das dann nicht klappt bzw. so ein sch*** im Output steht. Muss ich echt mal meinen Prof. drauf ansprechen... Vielleicht hat der ja eine Erklärung...

Vielen Dank für deine Mühe. Das gilt natürlich auf für Matjes. (Hätte Reitzi nicht jetzt schon die Lösung präsentiert, hätt ich mich heute mal mit deienm Makro beschäftigt. ;-)

Greetz
M.
 
Thema:

JAVA: alle Kombination gegebener Zeichen

ANGEBOTE & SPONSOREN

Statistik des Forums

Themen
113.838
Beiträge
707.961
Mitglieder
51.491
Neuestes Mitglied
haraldmuc
Oben