9
votes

Générateur de permutation sur c

J'ai besoin d'un simple algorithme de générateur de permutation pouvant être appliqué sur un langage C simple.


3 commentaires

Alors pourquoi la question est-elle marquée C ++? En C ++, vous pouvez utiliser std :: Next_permutation.


duplicailler possible de Existe-t-il de meilleures méthodes pour faire la permutation de chaîne?


En outre, vous pouvez toujours vérifier les sources de STL NEXT_PERMUTATION, l'algorithme n'est pas si difficile.


5 Réponses :


7
votes

permutes sur les nombres:

Pour utiliser chaque permutation, vous devez connecter jusqu'à la fonction d'impression. P>

#include <stdio.h>
#include <stdlib.h>

/**
   Read a number, N, from standard input and print the
   permutations.
 */

void print(const int *v, const int size)
{
  if (v != 0) {
    for (int i = 0; i < size; i++) {
      printf("%4d", v[i] );
    }
    printf("\n");
  }
} // print


void swap(int *v, const int i, const int j)
{
  int t;
  t = v[i];
  v[i] = v[j];
  v[j] = t;
}


void rotateLeft(int *v, const int start, const int n)
{
  int tmp = v[start];
  for (int i = start; i < n-1; i++) {
    v[i] = v[i+1];
  }
  v[n-1] = tmp;
} // rotateLeft


void permute(int *v, const int start, const int n)
{
  print(v, n);
  if (start < n) {
    int i, j;
    for (i = n-2; i >= start; i--) {
      for (j = i + 1; j < n; j++) {
    swap(v, i, j);
    permute(v, i+1, n);
      } // for j
      rotateLeft(v, i, n);
    } // for i
  }
} // permute


void init(int *v, int N)
{
  for (int i = 0; i < N; i++) {
    v[i] = i+1;
  }
} // init


int main()
{
    int *v = (int*) malloc(sizeof(int)*10);
    init(v, 10);
    permute(v, 0, 10);
    free(v);
}


2 commentaires

Ceci est CODE C ++, non C. Cependant, il peut être facilement transformé en Code C: S / nouveau int [10] / MALLOC (10 * Tailleof (int)) / et S / S / Supprimer [] V / GRATUIT (V) /


Y a-t-il une référence à la littérature pour affirmer cet algorithme est correct? Par exemple. en.wikipedia.org/wiki/heap's_algorithme (que cette solution n'est pas)



2
votes

Ceci est un algorithme classique trouvé (entre autres endroits) dans le TAOCP de Knuth.

Voici un exemple que j'ai utilisé pour un problème d'Euler de projet. Il crée toutes les permutations d'une chaîne dans l'ordre lexicographique et les imprime à STDOUT. P>

#include<stdio.h>
int main()
{
        char set[10]="0123456789";
        char scratch;
        int lastpermutation = 0;
        int i, j, k, l;
        printf("%s\n",set);
        while (!lastpermutation)
        {
                //find largest j such that set[j] < set[j+1]; if no such j then done
                j = -1;
                for (i = 0; i < 10; i++)
                {
                        if (set[i+1] > set[i])
                        {
                                j = i;
                        }
                }
                if (j == -1)
                {
                        lastpermutation = 1;
                }
                if (!lastpermutation)
                {
                        for (i = j+1; i < 10; i++)
                        {
                                if (set[i] > set[j])
                                {
                                        l = i;
                                }
                        }
                        scratch = set[j];
                        set[j] = set[l];
                        set[l] = scratch;
                        //reverse j+1 to end
                        k = (9-j)/2; // number of pairs to swap
                        for (i = 0; i < k; i++)
                        {
                                scratch = set[j+1+i];
                                set[j+1+i] = set[9-i];
                                set[9-i] = scratch;
                        }
                        printf("%s\n",set);
             }
        }
        return 0;
}


0 commentaires

3
votes

tout

J'ai trouvé des algorithmes de générer des permutations dans l'ordre lexicographique de l'art de la programmation informatique (TACP):

http://fr.wikipedia.org/wiki/permutation#Generation_in_lexicographic_order < / p>

génération dans l'ordre lexicographique Il existe de nombreuses façons de générer systématiquement toutes les permutations d'une séquence donnée [citation requise]. Un algorithme classique, à la fois simple et flexible, est basé sur la recherche de la prochaine permutation dans les commandes lexicographiques, s'il existe. Il peut gérer des valeurs répétées, pour lesquelles il génère des permutations multiisettes distinctes une fois. Même pour des permutations ordinaires, il est significativement plus efficace que de générer des valeurs pour le code Lehmmer dans l'ordre lexicographique (éventuellement à l'aide du système de numéro de factoriel) et de la convertir à des permutations. Pour l'utiliser, on commence par trier la séquence d'ordre croissant (qui donne sa permutation minimale lexicographiquement), puis répète de faire progresser la prochaine permutation tant que l'on a été trouvé. La méthode remonte à Narayana Pandita au XIVe siècle Inde et a été fréquemment redécouverte depuis.

L'algorithme suivant génère la prochaine permutation lexicographiquement après une permutation donnée. Cela change la permutation donnée en place.

  1. Trouvez le plus grand index k tel qu'un [k]
  2. trouver le plus grand index L tel qu'un [k]
  3. Swap avec un [l] [k].
  4. Inverser la séquence à partir d'une [k + 1] jusqu'à et y compris le dernier élément d'un [n].

    Après l'étape 1, on sait que tous les éléments strictement après la position k former une séquence faiblement décroissante, donc pas de permutation de ces éléments le faire avancer dans l'ordre lexicographique; à une avance doit augmenter un [k]. Etape 2 trouve la plus petite valeur a [L] pour remplacer un [k] de, et en les échangeant à l'étape 3 feuilles de la séquence après la position k dans l'ordre faiblement décroissante. L'inversion de cette séquence dans l'étape 4 produit alors sa permutation lexicographiquement minimale, et le successeur lexicographique de l'état initial pour la séquence entière


0 commentaires

1
votes

Voici une solution récursive simple pour produire toutes les permutations d'un ensemble de caractères transmis sur la ligne de commande:

#include <stdio.h>
#include <string.h>

int perm(const char *src, int len, char *dest, char *destbits, int n) {
    if (n == len) {
        printf("%.*s\n", len, dest);
        return 1;
    } else {
        int count = 0;
        for (int i = 0; i < len; i++) {
            if (destbits[i] == 0) {
                destbits[i] = 1;
                dest[n] = src[i];
                count += perm(src, len, dest, destbits, n + 1);
                destbits[i] = 0;
            }
        }
        return count;
    }
}

int main(int argc, char *argv[]) {
    const char *src = (argc > 1) ? argv[1] : "123456789";
    int len = strlen(src);
    char dest[len], destbits[len];

    memset(destbits, 0, sizeof destbits);
    int total = perm(src, len, dest, destbits, 0);
    printf("%d combinations\n", total);

    return 0;
}


0 commentaires

1
votes

Je cherche quelque chose de plus itératif, puis je mettez en œuvre ma version médiocre. Je peux voir des optimisations, mais pour l'instant, cela m'aide. J'espère que cela aide tout le monde.

#include <stdio.h>
#include <stdlib.h>

#define PERM_T int
#define PERM_T_PFLAG "%d"

void swap(PERM_T *array, int i, int j) {
  PERM_T aux = array[i];
  array[i] = array[j];
  array[j] = aux;
}

void print_array_perm(PERM_T *array, int n) {
  printf("[");
  n -= 1;
  for (int i = 0; i < n; i++) {
    printf(PERM_T_PFLAG", ", array[i]);
  }
  if (n >= 0)
    printf(PERM_T_PFLAG, array[n]);
  printf("]\n");
}

void print_array_int(int *array, int n) {
  printf("[");
  n -= 1;
  for (int i = 0; i < n; i++) {
    printf("%d, ", array[i]);
  }
  if (n >= 0)
    printf("%d", array[n]);
  printf("]\n");
}

void copy_array_T(
  PERM_T *src, PERM_T *dst,
  int start, int end) {
  for (int i = start; i < end; i++) {
    dst[i] = src[i];
  }
}

void copy_array_int(
  int *src, int *dst,
  int start, int end) {
  for (int i = start; i < end; i++) {
    dst[i] = src[i];
  }
}

void rotate_array(
  PERM_T *array,
  int start, int end) {
  PERM_T aux = array[start];
  copy_array_T(
    array + 1, array, start, end);
  array[end - 1] = aux;
}

int factorial(int n) {
  int result = 1;
  while (n > 1) {
    result *= n;
    n--;
  }
  return result;
}

typedef struct {
  PERM_T *data;
  int length;
  int *ks;
  int kn;
  int _i;
} Perm;

Perm perm_(
  PERM_T *data, PERM_T *array, int n) {
  copy_array_T(array, data, 0, n);
  int kn = n > 1 ? n - 1 : 0;
  
  int *ks = kn
    ? malloc(sizeof(PERM_T) * kn)
    : NULL;
  for (int i = 0; i < kn; i++)
    ks[i] = i;

  int max_iterations = factorial(n);
  Perm p = {
    .data = data,
    .length = n,
    .ks = ks,
    .kn = kn,
    ._i = max_iterations
  };
  return p;
}

Perm perm(PERM_T *array, int n) {
  PERM_T *data = 
    malloc(sizeof(PERM_T) * n);
  return perm_(data, array, n);
}

Perm copy_perm(Perm p) {
  Perm copy = perm(p.data, p.length);
  copy_array_int(p.ks, copy.ks, 0, p.kn);
  return copy;
}

void clear_perm(Perm* p) {
  free(p->data);
  if (p->kn) free(p->ks);
}

int completed_perm(Perm *p) {
  return p->_i < 1;
}

void next_perm_self(Perm *p) {
  int n = p->length;

  if (completed_perm(p)) return;

  p->_i--;
  int k = p->kn - 1;
  int *ks = p->ks;
  PERM_T *data = p->data;

  if (ks[k] + 1 != n) {
    rotate_array(data, k, n);
    ks[k] += 1;
  } else {
    while (k >= 0 && ks[k] + 1 == n) {
      ks[k] = k;
      rotate_array(data, k, n);
      k -= 1;
    }
    if (k >= 0) {
      rotate_array(data, k, n);
      ks[k] += 1;
    }
  }
}

Perm next_perm_(Perm *p) {
  Perm next = copy_perm(*p);
  next_perm_self(&next);
  return next;
}

Perm next_perm(Perm *p) {
  Perm next = next_perm_(p);
  clear_perm(p);
  return next;
}

void print_perm(Perm p) {
  print_array_perm(p.data, p.length);
}

void print_perm_(Perm p) {
  printf("%p\n", p.data);
  print_perm(p);
  print_array_int(p.ks, p.kn);
}

Perm next_print(Perm *p) {
  print_perm(p);
  return next_perm(p);
}

void next_print_self(Perm *p) {
  print_perm(*p);
  next_perm_self(p);
}

int main() {
  int a1[] = {1,2,3,4,5};
  Perm p = perm(a1, 5);
  
  int i = 0;
  while (!completed_perm(&p)) {
    printf("%3d ", i++);
    // p = next_print(&p);
    next_print_self(&p);
  }

  clear_perm(&p);
  return 0;
}


0 commentaires