C: eliminare doppioni generati da rand

Se avete dubbi o domande sulla programmazione in generale, fatele qui
Rispondi
simo91
Arciere
Messaggi: 237
Iscritto il: 24 agosto 2008, 12:53
Località: Bologna
Contatta:

Messaggio da simo91 » 12 settembre 2009, 12:30

Ciao a tutti e buona giornata :) Volevo provare ad implementare un modo per eliminare i numeri doppi, solo che non ho idee. Il mio programma estrae i numeri del SuperEnalotto quindi se per caso un numero appare due volte non va bene :( Qualcuno sa come fare? vi allego il sorgente. Grazie di cuore :D

Codice: Seleziona tutto

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

int main() {

  // i = variabile per ciclo for
  // n = variabile per ciclo for
  // c = variabile per il numero SuperStar
  // v = vettore per bubble sort
  int i, n, c = 0, v[6];
  
  // q = variabile per la domanda
  char q;

  int bubbleSort(int numbers[], int array_size);

  // insemina rand
  srand(time(NULL));
  
  printf("Vuoi giocare il numero SuperStar? <S/n> ");
  scanf("%c", &q);

  // diminuisce c in modo che non venga stampato il numero SuperStar
  if (q == 'n' || q == 'N') {
    --c;
    printf("Schedina SuperEnalottonGiocata 01 | Giocata 02n");
  }
  
  else
    printf("Schedina SuperEnalottonGiocata 01 | Giocata 02 | Numero SuperStarn");

  // ciclo per le 2 estrazioni
  for (i = 0; i < 2; ++i) {

  // assegna i 6 numeri al vettore
  for (n = 0; n < 6; ++n)
    v[n] = rand() % 90 + 1;
  
  // ordina il vettore
  bubbleSort(v, 6);

  // stampa a video il vettore
  for (n = 0; n < 6; ++n)
    printf("%d ", v[n]);

  printf("n");
  ++c;
  
  // stampa a video il numero SuperStar
  if (c == 2)
    printf("%dn", v[0] = rand() % 90 + 1);
  
  }
  
  return 0;
}

// funzione bubbleSort
int bubbleSort(int numbers[], int array_size)
{
  int i, j, temp;

  for (i = (array_size - 1); i > 0; i--)
  {
    for (j = 1; j <= i; j++)
    {
      if (numbers[j-1] > numbers[j])
      {
        temp = numbers[j-1];
        numbers[j-1] = numbers[j];
        numbers[j] = temp;
      }
    }
  }
  return 0;
}
Ultima modifica di simo91 il 12 settembre 2009, 13:03, modificato 1 volta in totale.
Arch Linux i686
Jabber, per chiunque: simo91@jabber.org - My blog

issproevolution
Arciere Provetto
Messaggi: 517
Iscritto il: 22 settembre 2007, 20:20
Località: /dev/null

Messaggio da issproevolution » 12 settembre 2009, 13:03

usa un algoritmo di ricerca per controllare se il numero e' gia' nell'array.. se lo e', ripeti l'estrazione..
;) ;)

simo91
Arciere
Messaggi: 237
Iscritto il: 24 agosto 2008, 12:53
Località: Bologna
Contatta:

Messaggio da simo91 » 12 settembre 2009, 13:25

issproevolution ha scritto:usa un algoritmo di ricerca per controllare se il numero e' gia' nell'array.. se lo e', ripeti l'estrazione..
;) ;)
praticamente una specie di bubble sort con il confronto dei numeri :) giusto?
Arch Linux i686
Jabber, per chiunque: simo91@jabber.org - My blog

Howl
Arciere Provetto
Messaggi: 435
Iscritto il: 28 luglio 2008, 19:32

Messaggio da Howl » 12 settembre 2009, 13:46

simo91 ha scritto:
issproevolution ha scritto:usa un algoritmo di ricerca per controllare se il numero e' gia' nell'array.. se lo e', ripeti l'estrazione..
;) ;)
praticamente una specie di bubble sort con il confronto dei numeri :) giusto?
No. Molto più semplice: passi in rassegna l'array con un semplice ciclo for e confronti il numero appena estratto con ogni numero contenuto nell'array.
Se l'array è di grosse dimensioni (ma mi pare di capire non sia il tuo caso) ed è già ordinato puoi invece usare un algoritmo di ricerca binaria che si basa semplicemente sul cosiddetto "teorema degli zeri".

simo91
Arciere
Messaggi: 237
Iscritto il: 24 agosto 2008, 12:53
Località: Bologna
Contatta:

Messaggio da simo91 » 14 settembre 2009, 10:27

Ho aggiunto queste poche righe e così dovrebbe andare bene:

Codice: Seleziona tutto

  // rileva doppioni
  for (n = 1; n < 6; ++n) {
    if (v[n] == v[n - 1])
      goto error;
  }
queste subito dopo l'ordinamento del vettore e subito prima che i numeri vengano stampati a schermo, poi ho messo

Codice: Seleziona tutto

error:
prima dell'inizio dei due cicli per le estrazioni. So che non viene consigliato l'uso di goto però in questo caso mi sembrava la soluzione più semplice e pulita, altre idee sono sempre ben accette :) grazie mille !!
Arch Linux i686
Jabber, per chiunque: simo91@jabber.org - My blog

simo91
Arciere
Messaggi: 237
Iscritto il: 24 agosto 2008, 12:53
Località: Bologna
Contatta:

Messaggio da simo91 » 14 settembre 2009, 11:21

Ho dovuto modificare un pò il programma perchè dopo l'inserimento di quelle righe nascevano altri problemi, ora dovrebbe essere tutto ok, vi lascio il sorgente nel caso vi possa servire, saluti.

Codice: Seleziona tutto

// superenalotto.c 14/09/2009

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

int main() {

  // n = variabile per i cicli for
  // c = variabile per il numero SuperStar
  // v = vettore per la prima estrazione
  // z = vettore per la seconda estrazione
  int n, c = 1, v[6], z[6];
  
  // q = variabile per la domanda
  char q;

  int bubbleSort(int numbers[], int array_size);

  // insemina rand
  srand(time(NULL));
  
  printf("Vuoi giocare il numero SuperStar? <S/n> ");
  scanf("%c", &q);

  // diminuisce c in modo che non venga stampato il numero SuperStar
  if (q == 'n' || q == 'N') {
    --c;
    printf("Schedina SuperEnalottonGiocata 01 | Giocata 02n");
  }
  
  else
    printf("Schedina SuperEnalottonGiocata 01 | Giocata 02 | Numero SuperStarn");
  
  // ripete le estrazioni se vengono trovati doppioni
  error:

  // assegna i 6 numeri al vettore v
  for (n = 0; n < 6; ++n)
    v[n] = rand() % 90 + 1;
  
  // ordina il vettore v
  bubbleSort(v, 6);

  // rileva doppioni nel vettore v
  for (n = 1; n < 6; ++n) {
    if (v[n] == v[n - 1])
      goto error;
  }

  // assegna i 6 numeri al vettore z
  for (n = 0; n < 6; ++n)
    z[n] = rand() % 90 + 1;

  // ordina il vettore z
  bubbleSort(z, 6);

  // rileva doppioni nel vettore z
  for (n = 1; n < 6; ++n) {
    if (z[n] == z[n - 1])
      goto error;
  }

  // stampa a video il vettore v
  for (n = 0; n < 6; ++n)
    printf("%d ", v[n]);

  printf("n");

  // stampa a video il vettore z
  for (n = 0; n < 6; ++n)
    printf("%d ", z[n]);

  printf("n");
  
  // stampa a video il numero SuperStar
  if (c == 1)
    printf("%dn", v[0] = rand() % 90 + 1);
  
  return 0;
}

// funzione bubbleSort
int bubbleSort(int numbers[], int array_size) {
  
  int i, j, temp;

  for (i = (array_size - 1); i > 0; i--) {
    for (j = 1; j <= i; j++) {
      if (numbers[j - 1] > numbers[j]) {
        temp = numbers[j - 1];
        numbers[j - 1] = numbers[j];
        numbers[j] = temp;
      }
    }
  }
  return 0;
}
Ultima modifica di simo91 il 14 settembre 2009, 11:22, modificato 1 volta in totale.
Arch Linux i686
Jabber, per chiunque: simo91@jabber.org - My blog

Cif
Novello Arciere
Messaggi: 34
Iscritto il: 27 agosto 2007, 9:53
Località: Vicenza

Messaggio da Cif » 14 settembre 2009, 19:27

O_O Paura...

Il programma sopra è un monumento all'inefficienza... Puoi fare molto di meglio... E ti prego, disimpara i GoTo, sono peggio della peste o della AH1N1...
- In development -

simo91
Arciere
Messaggi: 237
Iscritto il: 24 agosto 2008, 12:53
Località: Bologna
Contatta:

Messaggio da simo91 » 14 settembre 2009, 19:34

Cif ha scritto:O_O Paura...

Il programma sopra è un monumento all'inefficienza... Puoi fare molto di meglio... E ti prego, disimpara i GoTo, sono peggio della peste o della AH1N1...
Bhè a me interessa che il programma funzioni, e meglio di così non so fare. Il goto è comodissimo messo lì :D Se hai idee migliori aiutami pure..
Arch Linux i686
Jabber, per chiunque: simo91@jabber.org - My blog

Nss
Novello Arciere
Messaggi: 50
Iscritto il: 23 gennaio 2008, 10:20

Messaggio da Nss » 14 settembre 2009, 19:48

ma scusami scusami scusami...
quanti numeri sono? 90? allora crea un array di 90 posizioni e metti uno sul numero che è uscito e 0 negli altri.. per controllare se un numero N è uscito fai USCITI[N]!=1
Slackware -> Gentoo -> Archlinux
http://lanziani.com/blog/

aleph
Robin Hood
Messaggi: 1530
Iscritto il: 12 febbraio 2008, 16:30
Contatta:

Messaggio da aleph » 14 settembre 2009, 22:25

quoto la soluzione di nss, quando devi lavorare su un numero finito basso di valori il counting è l'approccio migliore ;)

anche il goto si può sostituire con un while o equivalente . .

ecco una soluzione alternativa (fatta in 5min quindi non necessariamente corretta;)

Codice: Seleziona tutto

// superenalotto.c 14/09/2009

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

int main() {

  // n = variabile per i cicli for
  // c = variabile per il numero SuperStar
  // v = vettore per la prima estrazione
  // z = vettore per la seconda estrazione
  int n, c = 1, v[6], z[6];
  
  // q = variabile per la domanda
  char q;

  int numeri_gia_usciti[91];
 

  // insemina rand
  srand(time(NULL));
  
  printf("Vuoi giocare il numero SuperStar? <S/n> ");
  scanf("%c", &q);

  // diminuisce c in modo che non venga stampato il numero SuperStar
  if (q == 'n' || q == 'N') {
    --c;
    printf("Schedina SuperEnalottonGiocata 01 | Giocata 02n");
  }
  
  else
    printf("Schedina SuperEnalottonGiocata 01 | Giocata 02 | Numero SuperStarn");
  
   for(n=1;n<=90;n++)
	 numeri_gia_usciti[n]=0;
   for (n = 0; n < 6; ++n){
	 do{   
        v[n] = rand() % 90 + 1;
	}while(numeri_gia_usciti[v[n]]);
	numeri_gia_usciti[v[n]]=1;
   }
  

  // assegna i 6 numeri al vettore z
  for(n=1;n<=90;n++)
	numeri_gia_usciti[n]=0;
  for (n = 0; n < 6; ++n){
    do{   
	    z[n] = rand() % 90 + 1;
    }while(numeri_gia_usciti[z[n]]);
    numeri_gia_usciti[z[n]]=1;
   }

  // stampa a video il vettore v
  for (n = 0; n < 6; ++n)
    printf("%d ", v[n]);

  printf("n");

  // stampa a video il vettore z
  for (n = 0; n < 6; ++n)
    printf("%d ", z[n]);

  printf("n");
  
  // stampa a video il numero SuperStar
  if (c == 1)
    printf("%dn", v[0] = rand() % 90 + 1);
  
  return 0;
}
ps:il bubblesort è abbastanza scarso come algoritmo . . se proprio devi, usa un merge (o una funzione sort nativa da libreria ;) )
ImmagineOutside of a dog, computers are a man's best friend, inside a dog it's too dark to type.

Howl
Arciere Provetto
Messaggi: 435
Iscritto il: 28 luglio 2008, 19:32

Messaggio da Howl » 15 settembre 2009, 10:50

aleph ha scritto:quoto la soluzione di nss, quando devi lavorare su un numero finito basso di valori il counting è l'approccio migliore ;)
Ma stiamo parlando di 6 numeri! Forse è la soluzione più elegante, però non è che si guadagni molto in efficienza (anche perché devi inizializzare un array di 90 numeri, ma sopratutto perché con valori di n così bassi dovremmo confrontare il tempo di esecuzione di ogni operazione per guadagnare alla fine 1 ciclo di clock se ci va bene ).
ps:il bubblesort è abbastanza scarso come algoritmo . . se proprio devi, usa un merge (o una funzione sort nativa da libreria ;) )
Ripeto: stiamo parlando di 6 numeri! Usare il merge sort, che tra l'altro non è poi così intuitivo come il bubble sort, è totalmente controproducente. Piuttosto usa il selection sort che per valori di n bassi è molto efficiente e sicuramente più intuitivo del merge.

Sul goto: sono d'accordo che qui poteva essere evitato, ma comunque non cerchiamo di imparare quello che ci hanno insegnato a scuola come un dogma: il goto rimane ancora l'unico modo per implementare un decente (anche se forse un po' "triviale") meccanismo di gestione degli errori in C.

aleph
Robin Hood
Messaggi: 1530
Iscritto il: 12 febbraio 2008, 16:30
Contatta:

Messaggio da aleph » 15 settembre 2009, 14:35

è una questione di approcci . . io preferisco sempre usare algoritmi per quanto possibile scalabili, di modo che se devo modificare il programma non ho problemi . . il select forse è un pò esagerato (dipende quanto il compilatore può ottimizzare l'azzeramento), però genera del codice più compatto e sicuramente più scalabile . . per dire si poteva anche tenere un vettore dei numeri usciti e fare il controllo su di quello, in questo caso sarebbe più efficiente . . . questione di gusti :P . .

per il goto: io preferisco evitarlo se posso . . gli errori recuperabili preferisco gestirli con un while, quelli irrecuperabili con un error() o un return ERROR_CODE . . . anche qui sono gusti :P . .

esempio più efficiente

Codice: Seleziona tutto

     int numeri_gia_usciti[6],i;
   for (n = 0; n < 6; ++n){
	 loop:
	 v[n] = rand() % 90 + 1;
      for(i=0;i<n;i++)
			if(numenumeri_gia_usciti[i]==v[n])
				goto loop;
	numeri_gia_usciti[n]=v[n];
   }
e qua invece un goto lo uso perchè in c manca un costrutto break N o continue N per spezzare più livelli di cicli (odio il c che mi costringe a usare i goto :mad: , invero volendo si potrebbe usare una flag, ma odio le flag più ancora dei goto :P . . )
ImmagineOutside of a dog, computers are a man's best friend, inside a dog it's too dark to type.

Cif
Novello Arciere
Messaggi: 34
Iscritto il: 27 agosto 2007, 9:53
Località: Vicenza

Messaggio da Cif » 15 settembre 2009, 21:57

aleph ha scritto:e qua invece un goto lo uso perchè in c manca un costrutto break N o continue N per spezzare più livelli di cicli (odio il c che mi costringe a usare i goto :mad: , invero volendo si potrebbe usare una flag, ma odio le flag più ancora dei goto :P . . )
Si può evitare lo stesso, usando dei DO ... WHILE e WHILE con delle condizioni differenti per incrementare le variabili.
- In development -

fgr
Arciere
Messaggi: 188
Iscritto il: 2 dicembre 2008, 18:31

Messaggio da fgr » 16 settembre 2009, 11:23


Rispondi