Algorithmus für Programmieraufgabe gesucht

Mein Problem ist folgendes:

a b c d e f g h i j

Belegung 1) 0 1 2 3 4 5 6 7 8 9

Belegung 2) 0 1 2 3 4 5 6 7 9 8

Belegung 3) 0 1 2 3 4 5 6 8 7 9

Belegung 4) 0 1 2 3 4 5 6 8 9 7

… …

Belegung n) 2 9 0 3 6 5 8 7 4 1

Belegung n+1)2 9 0 3 6 7 1 4 5 8

… …

letzte Bel.) 9 8 7 6 5 4 3 2 1 0

Diese tabelle zeigt einige von unzähligen möglichen Belegungen der Buchstaben a bis j mit den Zahlen 0 bis 9. Die Belegungen sind geordnet. Ich muss den Algorithmus finden, der sich dahinter verbirgt, mit dem ich für jede beliebige Belegung die darauf folgende Belegung berechnen kann.

Sinn der Sache ist es, ein Programm zu schreiben, welches alle möglichen Belegungen der Reihe nach durchläuft. Das Programm soll ein mathematisches Rätel lösen können, in dem es darum geht, die korrekten Belegungen für die einzelnen Buchstaben zu finden, damit bestimmte mathematische Aussagen erfüllt sind. Das ist aber nebensächlich.

Ich suche wie gesagt den Algo, der sich dahinter verbirgt, der alle Belegungen entsprechend der Tabelle oben ausgehend von der ersten Belegung nacheinander berechnet. Wenn ich eine zufällige Belegung n erstelle, soll mithilfe des Algo die Belegung n+1 errechnet werden können.

Ich habe lange überlegt und bin leider zu keinem Ergebnis gekommen. Ich wäre sehr dankbar, wenn jemand eine Lösung für mich hätte. Und noch dankbarer wäre ich, wenn er/sie mir auch kurz erklären könnte, wie ich selbstständig zu dieser Lösung kommen kann. Ich finde einfach keinen Denkansatz.

Danke im Vorraus

mfg hastig

hallo hastig,
die Zauberworte hier heissen „Permutationen“ (die willst du nämlich haben) und Rekursion (damit lässt es sich machen).

In Kürze:
wenn du nur ein Element e1 hast, ist die Sache einfach

alle Permutationen sind: ( e1 )

bei zwei Elementen sind die möglichen Permutatioenn:
(e1 e2) und (e2 e1)

oder besser ausgedrückt:

nimmt jedes Element als erstes Element der Permutationen und hänge dann alle Permutationen der restlichen Elemente an.

also:
(e1 + alle Perm. von (e2) ) und
(e2 + alle Perm. von (e1) )

Jetzt kommt die Rekursion ins Spiel:

bei n Elementen (e1 … en) nimmst du jedes Element als als erstes und hängst an dieses alle Permutationen der anderen Elemente an.

(okay, das Thema ‚Performance‘ kriegen wir dann in der nächsten Lektion)

gruss
bernhard

http://www.bastisoft.de/pascal/klassiker.html

Moin Moin

das mathe-rätsel dazu :wink:
http://www.wer-weiss-was.de/cgi-bin/forum/showarchiv…

für den teil

Wenn ich eine
zufällige Belegung n erstelle, soll mithilfe des Algo die
Belegung n+1 errechnet werden können.

sicherlich die bessere und schnellere als die des kollegen, die man für

Ich suche wie gesagt den Algo, der sich dahinter verbirgt, der
alle Belegungen entsprechend der Tabelle oben ausgehend von
der ersten Belegung nacheinander berechnet.

wohl eher benutzt

implementiert sähe das so aus :wink:

**package sortierung;

public class Rater {
char[] anfang;
public static char[] topf = {
‚0‘, ‚1‘, ‚2‘, ‚3‘, ‚4‘, ‚5‘, ‚6‘, ‚7‘, ‚8‘, ‚9‘};

public Rater() {
anfang = new char[10];
for (int i = 0; i 1; i–) {
ret *= i;
}
return ret;
}

public char[] kombos(int n) {
//nur zum verständnis, pc fängt bei 0 an, mensch bei ^1
n–;
char[] ret = new char[10];
for (int stelle = 0; stelle 0) {
for (int i = 0, o = 0; i

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]**

Erstmal danke für Deine Antwort! Ich bin nicht sicher, das richtig verstanden zu haben. Im Falle dieser Tabelle würde ich also bei der 1. Permutation (Belegung)die Spalte h mit dem Wert 7 als meine erste Stelle betrachten. Ich hänge also alle möglichen Permutationen an die Stelle h(7) an, welches {8,9} und {9,8} wären. Somit sind die ersten beiden Permutationen 0123456789 und 0123456798. Danach betrachte ich die Spalte g mit dem Wert 6 als meine erste Stelle. Daran hänge ich wieder alle Permutationen der restlichen Zahlen, also {8,7,9}, {8,9,7}, {9,7,8} und {9,8,7}? Die 5. Belegung wäre dann also 123456987 und die 6. 123456987. Habe ich das so richtig verstanden , oder total falsch? Auch wenn ich das nun korrekt verstanden haben sollte, kann ich mir nicht erklären, wie ich nach diesem Schema von der belegung n (2903658741) zur Belegung n+1 (2903671458) gelangen soll.

Vermutlich sollte ich einfach mal ne Stunde Pause machen, damit der Groschen fällt. Liege ich denn mit meinem Beispiel überhaupt richtig, oder habe ich das alles komplett falsch verstanden?

mfg hastig

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Auch Dir vielen Dank für die Antwort. Ich möchte gerne eine eigene Implementierung schreiben. Einen unkommentierten Quellcode zu verstehen, dauert länger, als sich ihn selbst zu erarbeiten. Trotzdem vielen Dank für die Mühe, die Du Dir gemacht hast.

Ich möchte nur wissen, wie ich mit Papier und Bleistift vorgehe, wenn ich zu der zufälligen Belegung 9087654123 die nächste berechnen möchte.

Aus euren Posts weiss ich nun, wie ich festellen kann, die wievielte mögliche Belegung das ist. Ich hab jetzt auch eine der möglichen Implementierungen in Java gesehen, aber kann mir nicht einfach jemand erklären, wie man hier vorgeht?

Kann jemand Schritt-Für-Schritt die Belegung berechnen, die nach 2903658741 folgt? Ich möchte verstehen, wie das funktioniert. Ich sitze jetzt seit 8 Stunden an dieser Aufgabe. Ich glaub einfach, ich bin zu dumm dazu.

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

hallo ncohmal,

ich glaube, du hast es noch nicht ganz verstanden.

Was ich meinte war eher sowas (in sehr umgangssprachlichem Pseudocode):

sub alle\_permutationen (eingabeliste)
{

 # liefert zu einer eingabeliste eine Ausgabeliste mit allen
 # Permutationen

 initalisiere eine ausgabeliste;

 wenn eingabeliste nur ein element hat
 {
 ausgabeliste = ( eingabeliste )
 return ausgabeliste 
 }

# sonst
 for element 'e' in (eingabeliste)
 {
 restliste = eingabeliste ohne element 'e'

 alle\_restpermutationen = alle\_permutationen(restliste);
 # ^ da ist sie, die Rekursion!

 for restpermutation r in (alle\_restpermutationen)
 {
 neue\_permutation = (e, restpermutation)
 haenge 'neue\_permutation' an die 'ausgabeliste' an 
 }
 }
 return ausgabeliste
}

Dazu noch folgendes:

  • die Routine ist in dieser Form ein echter Speicherfresser (weil jede Menge Zwischenarrays gebildet und durch die Gegend geschoben werden).

  • schnell läuft das auch nicht.

  • wie ich aus deinem anderen Posting entnehme, willst du die Permutationen in einer bestimmten Reihenfolge haben (ich gebe dir die Perm n und die Routne liefert die (n+1). Perm,). Läuft in dieser Form auch nicht, nur das ‚Alles-oder-Nichts-Prinzip‘ zählt hier.

Sollte aber auch nur zum Zeigen des Prinizip sein, bessere / schnellere / elegantere Beispiele gibts aber haufenweise im Netz (frag mal einen Lisp-Programmierer, dann verstehen wir beide aber nichts mehr… :wink:))

gruss und nur nicht aufgeben!
bernhard

Moin Mathias (hast du nur ein t abgekriegt?),

sicherlich die bessere und schnellere als die des kollegen,

ist mir auch klar, dass man das Ganze wesentlich eleganter machen kann. Der Fragestellung nach zu urteilen, hatte der Frager aber von Rekursion noch nichts gehört, und da erschlägst du ihn gleich mit Code (und dann noch ohne PRE-Tag :=)

So wird doch nie was aus dem Bub!

gruss
bernhard

Danke nochmal, ich hab mir den Code nochmal in Ruhe angeschaut und bin auch ein bisschen schlauer geworden=). Der etwas umgangssprachliche Code von Dir hat dann alle Unklarheiten beseitigt^^. Bei mir soll die Sache folgendermassen funktionieren. Mein parameterloser Konstruktor erstellt die Anfangsbelegung (0123456789)in Form eines Arrays. Dann gibt es eine Methode, welche auf diese Anfangsbelegung angewendet die dementsprechend nächste Belegung errechnet. Ich arbeite mit nur einer Belegung, also einem Array, dass mit jedem Aufruf der Methode entsprechend in die nächste Belegung geändert wird. Dieses Vorgehen ist mir vorgeschrieben, es geht also nicht um Eleganz bzw. Performance. Um z.B. die 245. Belegung zu errechnen, wird die Methode 245 mal auf die Belegung angewendet.

Klingt simpel, ist auch so=) Dein Beispiel mit der Rekursion hat mir sehr weitergeholfen, nur nachdem ich erfolglos stundelang auf diese Zahlen gestarrt hatte, hab ich nicht mehr viel kapiert^^. Ein bisschen Pause wirkt Wunder.

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Also Rekursion ist mir nicht wirklich unbekannt, zumal das zu den Grundlagen gehört, mit denen wohl jeder sein Studium beginnt. Allerdings muss ich mich an gewisse Vorgaben halten und ich denke meine Fragestellung war auch recht einleuchtend. Der Code, mit dem mich der Kollege versucht hat zu erschlagen, hat mir letzendlich doch noch zum Erfolg verholfen^^. Im großen und ganzen ist es ja nichts anderes als das, was Du versucht hast mir zu erkären. Also nochmal Danke an Euch für Eure Hilfestellung!

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hallo Mathias,

auf

Mein Problem ist folgendes:
Belegung 1) 0 1 2 3 4 5 6 7 8 9
Belegung 2) 0 1 2 3 4 5 6 7 9 8
Belegung 3) 0 1 2 3 4 5 6 8 7 9
Belegung 4) 0 1 2 3 4 5 6 8 9 7
Belegung n) 2 9 0 3 6 5 8 7 4 1
Belegung n+1)2 9 0 3 6 7 1 4 5 8
letzte Bel.) 9 8 7 6 5 4 3 2 1 0

hast Du mit dem korrespondierenden Algorithmus
geantwortet:

public char[] kombos(int n) {
//nur zum verständnis, pc fängt bei 0 an, mensch bei ^1
n–;
char[] ret = new char[10];
for (int stelle = 0; stelle

Soweit soklar. Mir geht nur nicht ganz ein, wie Du
darauf gekommen bist, ich hätte den Algorithmus nicht
„erraten“ können :wink:

Um das ganze zu verstehen, habe ich es in C übersetzt
(weil ich in C eigentlich „denken“ kann :wink:, das hat
aber nichts geholfen.

 ...
 strncpy(dump, initseq, 10);
 for(cnt=0; cntMir ist nicht klar, welche Idee sich 
dahinter verbirgt. Könnt ihr mich aufklären?
Ist das etwas aus der Zahlentheorie?

Übrigens, auf einem A64/3400+ erhalte ich (für C)
folgende Laufzeit (gcc 4.0.1, -O3 -march=k8):

    
     RUN: 3,628,800 | 0123456789 =\> 9876543210, TOTAL: **4.22 sec**

Übrigens - bei den Sequenzen

    
     Belegung n) 2 9 0 3 6 5 8 7 4 1 
     Belegung n+1)2 9 0 3 6 7 1 4 5 8


ist n= <u>1,049,472</u>.

Grüße

CMБ

Wollte hier nochmal die Lösung posten, für alle die ich etwas verwirrt habe:

Der Trick an der Sache ist folgender: Man betrachtet die einzelnen Permutationen einfach als Zahlen, indem man die einzelnen Ziffern aneinanderreiht. Die erste Permutation laut der Vorgabetabelle entspricht also der Zahl 0123456789 bzw. 123456789. Die Letzte Permutation der Vorgabetabelle würde als Zahl 987654321 ergeben.

Na, fällt euch was auf? Die einzelnen Permutationen sind in aufsteigender Reihenfolge entsprechend ihres Zahlenwertes geordnet.

Betrachtet man mal die Zahlenwerte der beiden Beispielpermutationen n und n+1. So fällt auf, dass 2903671458 der nächstgrößte Wert nach 2903658741 ist, der sich aus den zur Verfügung stehenden Ziffern bilden lässt.

nach 2903671458 würde also der Wert 2903674158 folgen. Klingt ziemlich simpel oder? Den Algo werd ich dann auch mal als Code Posten, falls es jemanden interessiert^^

mfg hastig

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hallo!

Also der Algorithmus ist nicht ganz korrekt. Zumindest nicht, was meine Fragestellung anbelangt. Ich habe einen Algorithmus gesucht, der mir für jede beliebige Belegung, die nächste liefrt. Die Idee, die sich dahinter verbirgt ist einfach. Bildet man aus den einzelnen Ziffern jeder Permutation eine Zahl, so sind die entsprechenden Zahlen in dieser Liste aufsteigend angeordnet. Die größte Zahl, die sich bilden lässt ist die 9876543210 und die kleinste ist die 0123456789.

Im Falle der kleinsten Zahl 0123456789 vergleicht mein Algorithmus nun, ob die letzte Ziffer (9) größer ist, als die vorletzte (8). Da dies zutrifft, werden die beiden Zahlen getauscht. So erhält man die nächstgrößte Zahl 0123456798. Nun überprüft der Algo wieder, ob die letzte Ziffer (8) größer ist, als die vorletzte (9). Da dies zutrifft, springt man nun eine Stelle weiter nach links und überprüft nun wieder das Größenverhältnis. Da die 9 größer ist, als die 7, muss die 7 mit der nächstgrößten Zahl rechts von Ihr vertauscht werden. Das ist die 8. Also erhalte ich vorläufig 0123456897. Um allerdings die nächstgrößte Zahl zu erhalten, müssen alle Ziffern rechts von der 8 in aufsteigender Reihenfolge angeordnet werden. Somit erhalte ich 0123456879. Dies ist die nächstgrößte gesuchte Permutation.

Dieser Vorgang kann beliebig oft wiederholt werden, so dass ich am Ende bei der 9876543210 lande.

Im Erklären war ich nie besonders gut, ich hoffe, ich konnte das aber trotzdem veranschaulichen.

Dieser Algorithmus findet zu jeder x-beliebigen Permutation die nächstgrößere (sehr umgangssprachlich).

In meinem Code benutze ich zum Sortieren der Ziffern bubblesort. Falls jemand da eine bessere Idee hat, würde die mich sehr interessieren.

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Hallo Mathias,

public char[] kombos(int n) {
//nur zum verständnis, pc fängt bei 0 an, mensch bei ^1
n–;
char[] ret = new char[10];
for (int stelle = 0; stelle

Soweit soklar. Mir geht nur nicht ganz ein, wie Du
darauf gekommen bist, ich hätte den Algorithmus nicht
„erraten“ können :wink:

Um das ganze zu verstehen, habe ich es in C übersetzt
(weil ich in C eigentlich „denken“ kann :wink:, das hat
aber nichts geholfen.


strncpy(dump, initseq, 10);
for(cnt=0; cntMir ist nicht klar, welche Idee sich
dahinter verbirgt. Könnt ihr mich aufklären?
Ist das etwas aus der Zahlentheorie?

Übrigens, auf einem A64/3400+ erhalte ich (für C)
folgende Laufzeit (gcc 4.0.1, -O3 -march=k8):

RUN: 3,628,800 | 0123456789 => 9876543210, TOTAL:
4.22 sec

Übrigens - bei den Sequenzen

Belegung n) 2 9 0 3 6 5 8 7 4 1
Belegung n+1)2 9 0 3 6 7 1 4 5 8

ist n= 1,049,472.

Grüße

CMБ

moin Semjon

hast du auch den Link im 1.post angeschaut?
ich habe dort auch geantwortet, und die vorgehensweise schritt für schritt erklärt

sei mir nicht böse, wenn ichs nur verlinke und nicht wiederhole
http://www.wer-weiss-was.de/cgi-bin/forum/showarchiv…

es ist etwas aus der Kombinatorik

public char[] kombos(int n) {
//nur zum verständnis, pc fängt bei 0 an, mensch bei ^1
n–;

//leeres array machen

char[] ret = new char[10];
for (int stelle = 0; stelle

Ist die Frage jetzt gelöst oder noch offen?
Und geht es darum, die nächste Nummer zu finden, oder alle?

Die nächste findet man, in dem man

  1. von hinten die erste Ziffer sucht, die kleiner ist, als die vorhergehende.

  2. Diese vertauscht man mit der kleinsten Ziffer die größer ist als diese (und rechts von ihr steht).

  3. Dann nimmt man das, was rechts von ihr steht, und sortiert es.

    Beispiel
    0: 2903658741
    1: …58741
    2: …7.5…
    3: …1458
    x: 2903671458

Vorteil gegenüber Permutationen: auch bei ungünstigen Zahlen kommt man sehr schnell zu einem Ergebnis.
Die Dauer ist proportional zur Länge der Zahl.
Hier eine Implementierung:

import java.util.Arrays;

public class NextPerm
{
 private int arr [];
 /\*\* \*/
 public NextPerm (String param)
 {
 int i = 0;
 arr = new int [param.length ()];
 for (char c : param.toCharArray ())
 {
 arr[i++] = c - '0';
 }
 showArray ();
 findNextPerm ();
 showArray ();
 }

 private void findNextPerm ()
 {
 int pos = findFirstPositionNotAscendingFromRight ();
 if (pos \>= 0)
 {
 // System.out.println ("Pos not asc:\t" + pos);
 int pos2 = findPosOfSmallestDigitGreaterThanThatAtPos (pos);
 if (pos2 0; --i)
 {
 if (arr[i] \> arr[i-1])
 {
 return i-1;
 }
 }
 return -1;
 }

 /\*
 Arr: 2903658741
 Pos: 0123456789
 x: p 7 p=pos
 7 is the smallest Digit bigger than 5 on the right side
 We return 7 (because that is the position of 7 - not the value).
 \*/
 private int findPosOfSmallestDigitGreaterThanThatAtPos (int pos)
 {
 int digitToBig = arr[pos];
 int current = pos+1;

 for (int i = current; i digitToBig && arr[i] 
Wenn man alle Permutationen braucht, dann ist der Algorithmus aber nicht sehr effizient.

Hallo Stefan,

Ist die Frage jetzt gelöst oder noch offen?

Ich denke mal - gelöst.

Und geht es darum, die nächste Nummer zu finden, oder alle?

Sowohl als auch :wink:

[Algorithmus]

Danke für Deine gute Zusammenfassung. Ich hatte „damals“ eine
Weile damit herumgespielt und kam zu interessanten Ergebnissen
bezüglich der Laufzeit. Mich würde mal interessieren, wie
lange der Algorithmus in Java auf gängigen Maschinen braucht.

Vorteil gegenüber Permutationen: auch bei ungünstigen Zahlen
kommt man sehr schnell zu einem Ergebnis.
Die Dauer ist proportional zur Länge der Zahl.

Wahrscheinlich irgendwie „exponentiell“ ansteigend.

Hier eine Implementierung:
[Implementierung]

IMHO geht dieser Deiner nur mit Ziffern 0…9 (oder täusche
ich mich)? Um längere Sequenzen zu testen, könnte man ja
praktischerweise Buchstaben verwenden: ‚abcdefghijklm‘.

Wenn man alle Permutationen braucht, dann ist der Algorithmus
aber nicht sehr effizient.

In C (sorry, Java-Forum) erhalte ich folgende Laufzeiten
abhängig von der Stringlänge:

 PIII/700MHz, MS-VC 6.0
 ------------------------------------------------------------------------
 abc (L=3) -\> cba, 5 iter, 0.000 sek
 abcd (L=4) -\> dcba, 23 iter, 0.000 sek
 abcde (L=5) -\> edcba, 119 iter, 0.000 sek
 abcdef (L=6) -\> fedcba, 719 iter, 0.000 sek
 abcdefg (L=7) -\> gfedcba, 5039 iter, 0.000 sek
 abcdefgh (L=8) -\> hgfedcba, 40319 iter, 0.015 sek
 abcdefghi (L=9) -\> ihgfedcba, 362879 iter, 0.094 sek
 abcdefghij (L=10) -\> jihgfedcba, 3628799 iter, 0.812 sek
 abcdefghijk (L=11) -\> kjihgfedcba, 39916799 iter, 8.859 sek
 abcdefghijkl (L=12) -\> lkjihgfedcba, 479001599 iter, 106.141 sek

 Athlon XP/3400+ (2400MHz, single channel), gcc 3.3.3 -O6
 -------------------------------------------------------------------------
 abc (L=3) -\> cba, 5 iter, 0.000 sek
 abcd (L=4) -\> dcba, 23 iter, 0.000 sek
 abcde (L=5) -\> edcba, 119 iter, 0.000 sek
 abcdef (L=6) -\> fedcba, 719 iter, 0.000 sek
 abcdefg (L=7) -\> gfedcba, 5039 iter, 0.000 sek
 abcdefgh (L=8) -\> hgfedcba, 40319 iter, 0.000 sek
 abcdefghi (L=9) -\> ihgfedcba, 362879 iter, 0.030 sek
 abcdefghij (L=10) -\> jihgfedcba, 3628799 iter, 0.340 sek
 abcdefghijk (L=11) -\> kjihgfedcba, 39916799 iter, 3.570 sek
 abcdefghijkl (L=12) -\> lkjihgfedcba, 479001599 iter, 43.150 sek

Interessant ist hier imho, wie „schwerhändig“ sich der Athlon-64
bei der Suche verhält. Und das gegen einen popeligen P3-700
mit Via-Board :wink:

Also, das Problem ist zwar gelöst, aber dennoch von
Interesse. Ich hänge mal im Angang den C-Quelltext
dran.

Danke & Grüße

CMБ

-------------------------- [permutx.c] ------------------------------
#include 
#include 
#include 
#include 

 int SmlstLargerPos(const char \*s, int pos, int end) 
{
 int p=pos+1, pval=s[pos]; /\* finde den kleinsten Wert s[?] \*/
 const char \*q; /\* der größer ist als s[pos] \*/
 for(q=s+p; q pval && \*q s+start; q--) /\* suche rueckwaerts den ersten \*/  
 if(\*(q-1) gib dessen Position zurueck \*/  
}  
  
 int FindSolutionOf(char \*s, int len, int verbose) /\* Hier der Algorithmus \*/  
{  
 void SwitchPositions (char \*s, int p, int q); /\* vorwaerts-deklarationen \*/  
 void SortSequenceAt (char \*s, int len); /\* von Hilfsfunktionen \*/  
 int pos, nIter=0;  
   
 while( (pos = ReversionIncomplAt( s, 0, len )) \>= 0 ) {  
 if( verbose ) printf("\n%s", s);  
 SwitchPositions ( s, pos, SmlstLargerPos(s, pos, len) );  
 SortSequenceAt ( s+pos+1, len-pos-1 );  
 ++nIter;  
 }  
 return nIter;  
}  
/\* - - - [Eintrittspunkt] - - - - - - - - - - - - - - - - - - - - - - - \*/  
  
 int main()   
{  
 char sequence[] = "abcdefghijkl" /\*"0123456789"\*/;  
 char workseq[sizeof sequence];  
 int len, nIter, maxlen=strlen( sequence );  
 clock\_t nClocks;  
 memset(workseq, 0, sizeof workseq);  
   
 for(len=3; len %s, %d iter, %.3f sek\n", workseq, nIter,   
 (double)(clock()-nClocks)/CLOCKS\_PER\_SEC);  
 }  
 return 0;  
}  
  
/\* - - - [Hilfsfunktionen] - - - - - - - - - - - - - - - - - - - - - - \*/  
  
 void SwitchPositions(char \*s, int p, int q) /\* --- SwitchPositions --- \*/  
{   
 int t = s[p]; /\* tausche Inhalt vo s an \*/  
 s[p] = s[q], s[q] = t; /\* den Positionen p und q \*/  
}  
  
/\* Char-Vergleichsfunktion fuer qsort\*/  
int \_cmp\_( const void \*p1, const void \*p2 ) { return \*(char\*)p1 - \*(char\*)p2; }  
  
/\* qsort-wrapper (stdlib) \*/  
void SortSequenceAt( char \*s, int l ) { qsort(s, l, sizeof \*s, \_cmp\_); }

__END__

Hallo Semjon,
Mit ein paar Ersetzungen von char -> int verarbeitet mein Programm auch Strings, aber es sucht nur nach dem nächsten Element, und das dauert für:

time java NextPermChar akjihgfedcb
akjihgfedcb
cabdefghijk

real 0m0.347s
user 0m0.249s
sys 0m0.040s

aber wie man sieht wird hier ein Bug offenbar - statt b vorzuziehen wird c vorgezogen - muß ein Rangecheck sein.

Für das Erzeugen aller möglichen Permutationen habe ich ein anderes Programm.
Nachdem ich gestern diesen Thread fand, erinnerte ich mich an Sedgewicks Algorithmen und Datenstrukturen, und daß er Permutationen mit einem Stack erzeugt hat.
Da interessierte mich, ob ich das ohne ins Buch zu schauen hinbekomme.
Es klappt auch, aber die Laufzeit ist nicht berauschend.
Die Zeiten messe ich immer mit einem ‚time‘, so bleibt die Programmausgabe sauber, und das System rechnet die Zeiten der anderen Prozesse raus.
Hardware: Pentium Mobile 2Ghz:

time java PermRecursive abcdefgh \> /dev/null
user 0m0.622s
asux -\>~/proj/mini/forum \> time java PermRecursive abcdefghi \> /dev/null
user 0m4.974s
asux -\>~/proj/mini/forum \> time java -server PermRecursive abcdefghij \> /dev/null
user 0m37.992s
asux -\>~/proj/mini/forum \> time java -server PermRecursive abcdefghijk \> /dev/null
user 7m31.125s

Ich glaube Sedgewick machte das effizienter - muß ich nochmal nachschauen.
Hier meine Lösung:

import java.util.\*;
/\*\*
 PermRecursive

 @author Stefan Wagner
 @date Mi Apr 12 17:11:59 CEST 2006

\*/
public class PermRecursive
{
 /\*\* \*/
 public PermRecursive (String param)
 {
 int i = 0;
 ArrayList reservoir = new ArrayList ();
 for (char c : param.toCharArray ())
 {
 reservoir.add (c);
 }
 Stack result = new Stack ();
 buildPerm (result, reservoir);
 }

 public void buildPerm (Stack result, ArrayList reservoir)
 {
 ArrayList clown = (ArrayList ) reservoir.clone ();
 if (reservoir.isEmpty ())
 showStack (result);
 else
 for (Character c : reservoir)
 {
 ArrayList clown2 = (ArrayList ) clown.clone ();
 Stack neu = (Stack ) result.clone ();
 neu.push (c);
 clown2.remove (c);
 buildPerm (neu, clown2);
 }
 }

 public void showStack (Stack stack)
 {
 for (Character c : stack)
 System.out.print (c);
 System.out.println ();
 }

 /\*\* \*/
 public static void main (String args[])
 {
 String param = "0123";
 if (args.length == 1)
 {
 param = args[0];
 }
 new PermRecursive (param);
 }
}

Hallo nochmal!
Ich muß mich korrigieren, und Sedgewick in Schutz nehmen.
Er verwendet bei Permutationen keinen Stack.
So sieht meine Übersetzung nach Java aus:

/\*\* SedgewickPermutation

 Anregung: Sedgewick: Algorithmen in C++, (c) Adisson Wesley 1992 (1999), S. 711

 @author Stefan Wagner
 @date Do Apr 13 18:12:53 CEST 2006
\*/
public class Sp
{
 private int LEN;
 private int id = -1;
 private char[] val;

 private void writePerm ()
 {
 for (int i = 0; i 
Die Main-Methode ist ein Mixin aus dem alten Code - nur die Länge des Strings ist relevant, nicht der Inhalt, und es wird nur mit den Zeichen von 0-9 gearbeitet. 
Die Permutationen werden der Reihe nach, aufsteigend, gebildet, so daß ein Unterbrechen einen Schritt nach der Zahl, für die der Nachfolger gesucht wird, möglich ist - performanter als die Stack-Lösung ist es zu meiner Überraschung auch nicht, und für das Nachfolger-Suchen daher nur bedingt geeignet.

Hallo Stefan

jetzt erst eine Antwort, war über
Ostern weg. Deine Sedgewick-Idee
hat mich dazu gebracht, mich nochmal hinzusetzen.

So sieht meine Übersetzung nach Java aus:

/** SedgewickPermutation
public class Sp


}

Die Main-Methode ist ein Mixin aus dem alten Code - nur die
Länge des Strings ist relevant, nicht der Inhalt, und es wird
nur mit den Zeichen von 0-9 gearbeitet.

Nicht übel - und recht klar. Allerdings kann man
offenbar nur vom Anfang aus suchen - und nicht eine
beliebige Sequenz vorgeben - da die Bildung der
Sequenz in der Tiefe der Rekursion sozus. „verschlüsselt“
ist …

performanter als die Stack-Lösung ist es zu meiner
Überraschung auch nicht, und für das Nachfolger-Suchen
daher nur bedingt geeignet.

Stimmt, es ist ziemlich lahm. Kein vergleich zu Deiner
iterativen Java-Lösung von vor Ostern. Durch Java 1.5
und matrix.sort() ist das Ding deutlich schneller als
jede ‚naive‘ C-Lösung; ich bin beeindruckt!

Man müsste in C, um das zu schlagen, auch auf
einem int-Array arbeiten und auf die Bibliotheks-
qsort-Routine verzichten (zu viel overhead).

Wer ich mal versuchen, wenn ich Zeit habe :wink:

Übrigens: der rekursive Algorithmus wird
in Perl(!) extrem knapp und übersichtlich,
ich hab das mal spasseshalber probiert:

#!/usr/bin/perl -w

my @value;
my ($id, $param, $bound) = (-1);
 
 sub ShowPerm { 
 map [split //, $param]-\>[$\_-1], @value; 
 }

 sub Visit {
 $value[$\_[0] ] = ++$id;
 print ShowPerm, "\n" if($id == $bound);

 for my $t (0 .. $bound-1) { 
 Visit( $t ) if not $value[$t];
 }

 $value[$\_[0] ] = 0;
 --$id;
 }

$param = do { $ARGV[0] or "abcdefgh" };
$bound = length $param;

Visit 0; # start here

Da musste ich schon ein paar Leerzeilen
einfügen, damit da überhaupt noch was steht :wink:

Grüße & Danke für den Sedgewick-Tipp!

CMБ

Hallo,

Was nützt der schnellste Algorithmus, wenn er falsch ist?

Testfall alter Code:
java NextPerm 4326987
4326987
4328679
 private int findPosOfSmallestDigitGreaterThanThatAtPos (int pos)
 {
 int digitToBig = arr[pos];
 int current = pos+1;

// old, bug: for (int i = current; i 

Hallo Stefan

Was nützt der schnellste Algorithmus, wenn er falsch ist?

Aha, war mir nicht aufgefallen! Aber es wurden tatsächlich
nicht alle Permutationen erzeugt - allerdings eben doch genau
die, welche ich zum Testen verglich :wink:

// old, bug: for (int i = current; i

OK, nach den Änderungen ist der Java-Code ‚in etwa‘ so
schnell wie die ‚naive‘ C-Lösung.

Zum rekusrsiven Algorithmus von gestern:

  • a) es werden tatsächlich alle Permutationen erzeugt (Testcode: Anhang)

  • b) die Permutationen werden nicht in der vom OP geforderten Reihenfolge erzeugt

Trotzdem ist es ein recht schöner
und expressiver Algorithmus.

Grüße & Danke für die Korrektur. (Ich benutze diesen Thread
auch, um Java durch Übung zu vertiefen :wink:

Grüße

CMБ

Anhang: rekusrsiver Algorithmus mit Ausgabe der Anzahl der Permutationen

#!/usr/bin/perl -w
my ($laenge, $count, @para, @wert);
 
 sub ShowPermutation { 
 print join ('.', map $para[$\_-1], @wert), " - $count\n"; 
 }

 sub Visit {
 my ($pos, $tiefe) = @\_;
 $wert[$pos] = $tiefe;
 ShowPermutation ++$count if( $tiefe == $laenge ); 
 for my $trial ( 0 .. $laenge-1 ) {
 Visit( $trial, $tiefe+1 ) unless $wert[$trial];
 }
 $wert[$pos] = 0;
 }

@para = split //, (pop or "abcdefghi"); 
$laenge = scalar @para;

Visit 0, 0; # start here