J'apprends le retour en arrière et la récursivité et je suis bloqué par un algorithme pour imprimer toutes les permutations d'une chaîne. Je l'ai résolu en utilisant l'algorithme bell pour la permutation mais je ne suis pas capable de comprendre la méthode de récursivité. J'ai cherché sur le Web et trouvé ce code:
void permute(char *a, int i, int n)
{
int j;
if (i == n)
printf("%s\n", a);
else
{
for (j = i; j <= n; j++)
{
swap((a+i), (a+j));
permute(a, i+1, n);
swap((a+i), (a+j));
}
}
}
Comment cet algorithme fonctionne-t-il, je suis incapable de comprendre? J'ai même essayé de courir à sec!
Comment le retour en arrière est-il appliqué?
Et est-il plus efficace que l'algorithme de Bell pour le calcul de la permutation?
L'algorithme fonctionne essentiellement sur cette logique:
Toutes les permutations d'une chaîne X sont identiques à toutes les permutations de chaque caractère possible dans X, combinées à toutes les permutations de la chaîne X sans cette lettre.
C’est-à-dire que toutes les permutations de "abcd" sont
Cet algorithme en particulier, au lieu d'effectuer la récursion sur les sous-chaînes, effectue la récursion en place sur la chaîne d'entrée, sans utiliser de mémoire supplémentaire pour allouer des sous-chaînes. Le "retour en arrière" annule les modifications apportées à la chaîne, la laissant dans son état d'origine.
Le code a 2 problèmes , tous deux liés à n
, la longueur supposée de la chaîne. Le code for (j = i; j <= n; j++) { swap((a+i), (a+j)); ...
permute dans le caractère null '\0'
de la chaîne et donne les résultats tronqués de code. Vérifiez l'original (i == n)
qui devrait être (i == (n-1))
.
Le retour en arrière est appliqué en appelant swap()
deux fois efficace pour annuler son échange d'origine.
L'ordre de complexité est le même pour l'algorithme Bell.
#include <stdio.h>
void swap(char *a, char *b) { char t = *a; *a = *b; *b = t; }
void permute(char *a, int i, int n) {
// If we are at the last letter, print it
if (i == (n-1)) printf("%s\n", a);
else {
// Show all the permutations with the first i-1 letters fixed and
// swapping the i'th letter for each of the remaining ones.
for (int j = i; j < n; j++) {
swap((a+i), (a+j));
permute(a, i+1, n);
swap((a+i), (a+j));
}
}
}
char s[100];
strcpy(s, "ABCD");
permute(s, 0, strlen(s));
Le code que vous avez trouvé est correct! L'algorithme échange le caractère actuel de la chaîne avec tous les caractères suivants et appelle de manière récursive la fonction. C'est difficile à expliquer avec des mots. La figure ci-dessous peut vous aider.
La sauvegarde est effectuée dans le 2e échange pour inverser l’effet du premier échange, c’est-à-dire que nous revenons à la chaîne originale et allons maintenant échanger le caractère suivant du tableau avec le caractère actuel. La complexité temporelle de l'algo. est O (n * n!) puisque la boucle s'exécute n fois et que la fonction permute s'appelle n! fois. (Pour la 1ère itération, il est appelé n fois; pour la 2e itération (n-1) fois, etc.).
Source: http://www.geeksforgeeks.org/write-a-c-program-to-print-all-permutations-of-a-given-string/
La récursivité la simplifie vraiment:
public static void permutation(String str)
{
permutation("", str);
}
private static void permutation(String prefix, String str)
{
int n = str.length();
if (n == 0) {
System.out.println(prefix);
} else {
for (int i = 0; i < n; i++)
permutation(prefix + str.charAt(i), str.substring(0, i) + str.substring(i+1, n));
}
}
I create more specific but not efficient Program for permutation for general string.
It's work Nice way.
//ubuntu 13.10 and g++ compiler but it's works on any platform and OS
//All Permutation of general string.
#include<iostream>
#include<stdio.h>
#include<string>
#include<string.h>
using namespace std;
int len;
string str;
void permutation(int cnum)
{
int mid;
int flag=1;
int giga=0;
int dead=0;
int array[50];
for(int i=0;i<len-1;i++)
{
array[50]='\0';
dead=0;
for(int j=cnum;j<len+cnum;j++)
{
mid=j%len;
if(mid==cnum && flag==1)
{
cout<<str[mid];
array[dead]=mid;
dead++;
flag=0;
}
else
{
giga=(i+j)%len;
for(int k=0;k<dead;k++)
{
if((array[k]==giga) && flag==0)
{
giga=(giga+1)%len;
}
}
cout<<str[giga];
array[dead]=giga;
dead++;
}
}
cout<<endl;
flag=1;
}
}
int main()
{
cout<<"Enter the string :: ";
getline(cin,str);
len=str.length();
cout<<"String length = "<<len<<endl;
cout<<"Total permutation = "<<len*(len-1)<<endl;
for(int j=0;j<len;j++)
{
permutation(j);
}
return 0;
}
Pseudo code:
String permute(String a[])
{
if (a[].length == 1)
return a[];
for (i = 0, i < a[].length(); i++)
append(a[i], permute(a[].remove(i)));
}
def perms(s):
if len(s) < 1:
return [s]
ps = []
for i in range(0, len(s)):
head, tail = s[i], s[0:i] + s[i + 1:]
ps.extend([head + tailp for tailp in perms(tail)])
return ps
# include <stdio.h>
/* Function to swap values at two pointers */
void swap (char *x, char *y)
{
char temp;
temp = *x;
*x = *y;
*y = temp;
}
/* Function to print permutations of string
This function takes three parameters:
1. String
2. Starting index of the string
3. Ending index of the string. */
void permute(char *a, int i, int n)
{
int j;
if (i == n)
printf("%s\n", a);
else
{
for (j = i; j <= n; j++)
{
swap((a+i), (a+j));
permute(a, i+1, n);
swap((a+i), (a+j)); //backtrack
}
}
}
/* Driver program to test above functions */
int main()
{
char a[] = "ABC";
permute(a, 0, 2);
getchar();
return 0;
}