Nb aléatoires sans repetitions

romain chambard -  
KX Messages postés 16761 Date d'inscription   Statut Modérateur Dernière intervention   -
Bonjour,

je voudrais savoir s il est possible(et je pense que oui) de générer des nombres au hasard sans répétition; par exemple je voudrais rentrer dans un tableau 9 nombres allant de 1 a 9 générés de manière aléatoire sans répétition

merci de votre aide


A voir également:

2 réponses

KX Messages postés 16761 Date d'inscription   Statut Modérateur Dernière intervention   3 020
 
J'avais proposé plusieurs codes dans une discussion similaire en Java :
Nombre aleatoire sans répitition en java

Dans ton cas, c'est ma méthode alea2 qui correspond le mieux à ton problème.
Il est facile de la traduire en C, mais le plus intéressant c'est surement les explications que j'avais mis avant (même si elles ne faisaient pas l'unanimité)
1
KX Messages postés 16761 Date d'inscription   Statut Modérateur Dernière intervention   3 020
 
Conversion en C de mon code Java :

#include "stdlib.h"
#include "stdio.h"
#include "time.h"

// Choix de k valeurs aléatoire entre 0 et n-1
int* alea(int k, int n)
{
    int i,r;

    int* val = (int*) malloc(n*sizeof(int));
    for (i=0; i<n; i++)
        val[i]=i;
    
    int* tab = (int*) malloc(n*sizeof(int));
    
    for (i=0; i<k; i++)
    {
        r = rand() % (n-i);
        
        tab[i] = val[r];
        val[r] = val[n-i-1];
    }
    
    free(val);
    return tab;
}

int main()  
{
    srand(time(NULL));

    int i;
    int* tab = alea(9,9);
    for (i=0; i<9; i++)
        printf("%d ",tab[i]);
    free(tab);
    
    system("PAUSE");
    return 0;
}
0
nicocorico Messages postés 799 Date d'inscription   Statut Membre Dernière intervention   138
 
Sinon une autre solution fonctionnelle et simple consiste à remplir un tableau de la taille voulue avec les nombres croissants par exemple, donc dans ce cas un tableau de 9 cases contenant les chiffres de 1 à 9, puis de mélanger le contenu de ce tableau aléatoirement: il suffit donc de tirer des nombres aléatoires sans se préoccuper des répétitions et d'échanger la 1ère case du tableau avec celle correspondant au nombre tiré une trentaine de fois et voilà, le tableau contient un mélange des chiffres voulus sans répétitions...
0
nicocorico Messages postés 799 Date d'inscription   Statut Membre Dernière intervention   138
 
@KX ne maitrisant pas le C j'ai compris après coup que ma proposition est assez proche de la tienne, mais elle permet aussi quelques simplifications, je me suis permis de reprendre ton code pour le montrer:

#include "stdlib.h" 
#include "stdio.h" 
#include "time.h" 

// Choix de k valeurs aléatoire entre 0 et n-1 
int* alea(int k, int n) 
{ 
    int i,r, temp; 

    int* tab = (int*) malloc(n*sizeof(int)); 
    for (i=0; i<n; i++) 
        tab[i]=i; 

    for (i=0; i<k; i++) 
    { 
        r = rand() % (n-i); 
         
        temp = tab[r]; 
        tab[r] = tab[0];  
        tab[0] = temp; 
    } 
    
    return tab; 
} 

int main()   
{ 
    srand(time(NULL)); 

    int i; 
    int* tab = alea(9,9); 
    for (i=0; i<9; i++) 
        printf("%d ",tab[i]); 
    free(tab); 
     
    system("PAUSE"); 
    return 0; 
}
0
KX Messages postés 16761 Date d'inscription   Statut Modérateur Dernière intervention   3 020
 
J'ai fait une erreur de traduction Java-C, ou plus exactement une erreur de copier-coller, puisque j'avait donné une taille "n" au tableau "tab" (comme pour mon tableau "val") alors qu'il devait avoir une taille "k".

Bien sûr, dans le cas qui nous intéresse on a k==n et ça ne change rien, mais du coup mon erreur affecte aussi ton code, puisque le tableau de retour sera de taille "n" et non de taille "k".

Par contre il y a un problème dans ton code, parce que tu "remets en jeu" les nombres déjà échangés car tu les mets en première case (alors que moi je les mettait en dernière case) du coup la première case peut être à nouveau permutés alors que les dernières cases sont toujours bloquées.

Conséquence : avec ta "simplification", la plupart des cases restent dans l'ordre, on perd l'aléatoire...
0
nicocorico Messages postés 799 Date d'inscription   Statut Membre Dernière intervention   138
 
Ah oui c'est juste mon code n'est pas fonctionnel, je pensais trop au cas précis qui nous concernait pour lequel ce correctif convient, si je ne fait pas d'erreur, mes notions en C n'ayant pas évoluées depuis tout à l'heure!
Ma "simplification" ne faisait que limiter ton code qui est parfait pour son domaine d'application!

#include "stdlib.h" 
#include "stdio.h" 
#include "time.h" 

int* alea(int k) 
{ 
    int i,r, temp; 

    int* tab = (int*) malloc(k*sizeof(int)); 
    for (i=0; i<k; i++) 
        tab[i]=i; 

    for (i=0; i<k; i++) 
    { 
        r = rand() % (k); 
         
        temp = tab[r]; 
        tab[r] = tab[0];  
        tab[0] = temp; 
    } 
    
    return tab; 
} 

int main()   
{ 
    srand(time(NULL)); 

    int i; 
    int* tab = alea(9); 
    for (i=0; i<9; i++) 
        printf("%d ",tab[i]); 
    free(tab); 
     
    system("PAUSE"); 
    return 0; 
}
0
KX Messages postés 16761 Date d'inscription   Statut Modérateur Dernière intervention   3 020
 
Non, le problème est toujours là, en fait ce que je fais c'est que j'organise un "stock" de valeur au début du tableau, à l'étape i je tire donc aléatoirement un nombre entre les (n-i) valeurs restantes de mon stock, pour le permuter à la fin du stock (à la case n-i-1), puis grâce à l'incrémentation de i revient à diminuer le stock et donc de bloquer la case qui vient d'être permutée.

Mais ton code ne fait pas du tout ça, car tu tires à chaque fois un nombre entre 0 et k-1, ce qui signifie que tu peux permuter plusieurs fois la même case. Certaines cases ne seront donc jamais permutée, et seront toujours à la même place qu'au départ, c'est à dire que tab[i]==i...
0
nicocorico Messages postés 799 Date d'inscription   Statut Membre Dernière intervention   138
 
Oui tout à fait, mais c'est tout fait fonctionnel quand même puisqu'en fait il annule son action dans le seul cas où la même valeur sort deux fois de suite, sinon la valeur de la case 0 à changé entre temps! En fait on échange à chaque fois le contenu de la case précédemment tirée avec celui de la nouvelle case tirée au sort... Mais le faire "K" fois peut être un peu juste, il vaut mieux faire K*2 ou K*3 itérations pour être sûr du brassage.
Et quelque part, il n'est pas très grave que certaines cases restent inchangées... ce qui compte c'est qu'il y ait un certain mélange un peu partout, ce qui a pour conséquence de tout mélanger!
0