Nb aléatoires sans repetitions

Fermé
romain chambard - 10 nov. 2012 à 17:34
KX Messages postés 16741 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 30 mai 2024 - 11 nov. 2012 à 12:49
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


2 réponses

KX Messages postés 16741 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 30 mai 2024 3 016
10 nov. 2012 à 17:41
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 16741 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 30 mai 2024 3 016
10 nov. 2012 à 17:49
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 dimanche 19 juin 2011 Statut Membre Dernière intervention 3 juillet 2018 138
10 nov. 2012 à 21:12
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 dimanche 19 juin 2011 Statut Membre Dernière intervention 3 juillet 2018 138
Modifié par nicocorico le 10/11/2012 à 22:12
@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 16741 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 30 mai 2024 3 016
10 nov. 2012 à 22:39
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 dimanche 19 juin 2011 Statut Membre Dernière intervention 3 juillet 2018 138
10 nov. 2012 à 23:03
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 16741 Date d'inscription samedi 31 mai 2008 Statut Modérateur Dernière intervention 30 mai 2024 3 016
10 nov. 2012 à 23:16
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 dimanche 19 juin 2011 Statut Membre Dernière intervention 3 juillet 2018 138
Modifié par nicocorico le 10/11/2012 à 23:29
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