Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
Pascal - Rimozione duplicati
Forum - Pascal - Rimozione duplicati

Pagine: [ 1 2 ] Precedente | Prossimo
Avatar
Tommaso95 (Normal User)
Newbie


Messaggi: 17
Iscritto: 17/10/2012

Segnala al moderatore
Postato alle 18:11
Mercoledì, 17/10/2012
Ciao a tutti, sono nuovo e sto imparando a programmare con il Pascal sia a scuola sia per conto mio.

Ho creato qualche programma più o meno complesso (tutti relativamente facili alla fine) ma non riesco a saltarne fuori con questo che all'apparenza è semplicissimo ma ha un "pezzo" che mi crea problemi.

In pratica devo:
- Creare un array con 100 elementi
- Riempirlo con numeri da 1 a 100
- Controllare la presenza di eventuali doppioni e se ci sono sostituirli
- Stampare l'array.

Il codice che ho creato fino adesso è questo:
Codice sorgente - presumibilmente Delphi

  1. program test;
  2. uses crt;
  3.      type
  4.          tab = array[1..100] of integer;
  5.      var
  6.         ele:tab;
  7.  
  8. procedure carica_dati(var ele:tab);
  9.      var
  10.      a:byte;
  11. begin
  12.   randomize;
  13.      for a:=1 to 100 do
  14.            ele[a]:=random(100)+1;
  15. end;
  16.  
  17. procedure controllo_doppioni(var ele:tab);
  18.      var
  19.      a,pos:byte;
  20. begin
  21.       for a:=1 to 100 do begin
  22.            repeat
  23.  
  24.                          pos:=2;
  25.                          if (ele[a]<>ele[pos]) and (pos<=100) then
  26.                           begin
  27.                             pos:=pos+1;
  28.                           end
  29.                          else
  30.                            ele[pos]:=random(100)+1;
  31.            until
  32.                          pos>100;
  33.                 end;
  34. end;
  35.  
  36. procedure stampa_dati(ele:tab);
  37.     var
  38.     a:byte;
  39. begin
  40.      for a:=1 to 100 do
  41.           Write(ele[a]:5);
  42. end;
  43.  
  44. begin
  45. clrscr;
  46.        carica_dati(ele);
  47.            controllo_doppioni(ele);
  48.        stampa_dati(ele);
  49.  
  50.   readln;
  51. end.



I problemi\domande che ho sono due:
1) Perchè la procedura controllo non funziona? Mi interessa sapere più che altro concettualmente che erroe ho fatto
2) Perchè il nostro prof ha detto che i parametri che mettiamo tra parentesi dopo il nome della procedura possono essere o di input\output (se hanno il var) o solo di input se non lo hanno ma in ogni caso mi stampano l'array ? Se non si è capita questa domanda, perchè anche se tolgo il var mi stampa l'array? In teoria non è solo di input?

Grazie a tutti.

P.S. Purtroppo da questo primo mesi di informatica a scuola ho notato che è una materia ancora tralasciata da molti. In classe siamo solo in 3-4 a sapere qualcosa, gli altri non sanno nemmeno a cosa serve read o write :(

PM Quote
Avatar
Poggi Marco (Member)
Guru


Messaggi: 969
Iscritto: 05/01/2010

Segnala al moderatore
Postato alle 19:58
Mercoledì, 17/10/2012
Ciao!

La funzione non funziona essenzialmente per due motivi; alla variabile pos viene assegnato 1 all' inizio del loop interno, causando un ciclo infinito. Quando si trova un' uguaglianza, gli indici a e pos vanno reinizializzati; quando si modifica un valore, si deve ricontrollare tutto l' array.

l' identificatore var serve ad identificare in che modo avviene il passaggio delle variabili alle funzioni.

Senza -> il passaggio avviene " per valore "; ovvero si crea una copia della variabile.

Con var -> il passaggio avviene " per indirizzo "; qualsiasi modifica alla variabile locale, permane a quella indicata alla chiamata della funzione.

Ecco un esempio:
Codice sorgente - presumibilmente Delphi

  1. program passaggio;
  2. var a:integer;
  3.  
  4.  procedure passaggioPerValore(x:integer);
  5.  begin
  6.     x:=x+8; // la modifica è locale
  7.  end;
  8.  
  9.  procedure passaggioPerIndirizzo(var x:integer);
  10.  begin
  11.     x:=x+8; // modifica permanente
  12.  end;
  13.  
  14. begin
  15.        a:=5;
  16.        writeln('a vale ',a);
  17.        passaggioPerValore(a);
  18.        writeln('a vale ',a);
  19.        passaggioPerIndirizzo(a);
  20.        writeln('a vale ',a);
  21.        readln;
  22. end.


PM Quote
Avatar
Tommaso95 (Normal User)
Newbie


Messaggi: 17
Iscritto: 17/10/2012

Segnala al moderatore
Postato alle 20:06
Mercoledì, 17/10/2012
1) Ok, quindi dovrei prima dichiarare pos fuori dal reapeat. Per reinizializzare pos e a come posso fare?

2) Penso di avere capito. Nel mio programma perchè mi stampa l'array in ogni caso anche se tolgo il var?

Codice sorgente - presumibilmente Delphi

  1. program test;
  2. uses crt;
  3.      type
  4.          tab = array[1..100] of integer;
  5.      var
  6.         ele:tab;
  7.  
  8. procedure carica_dati(var ele:tab);
  9.      var
  10.      a:byte;
  11. begin
  12.   randomize;
  13.      for a:=1 to 100 do
  14.            ele[a]:=random(100)+1;
  15. end;
  16.  
  17. procedure controllo_doppioni(var ele:tab);
  18.      var
  19.      a,pos:byte;
  20. begin
  21.       for a:=1 to 100 do begin pos:=2;
  22.            repeat
  23.  
  24.  
  25.                          if (ele[a]<>ele[pos]) and (pos<=100) then
  26.                           begin
  27.                             pos:=pos+1;
  28.                           end
  29.                          else
  30.                 begin
  31.                    ele[pos]:=random(100)+1;
  32.                    pos:=1;
  33.                    a:=1;
  34.                 end;
  35.            until
  36.                          pos>100;
  37.                 end;
  38. end;
  39.  
  40. procedure stampa_dati(ele:tab);
  41.     var
  42.     a:byte;
  43. begin
  44.      for a:=1 to 100 do
  45.           Write(ele[a]:5);
  46. end;
  47.  
  48. begin
  49. clrscr;
  50.        carica_dati(ele);
  51.            controllo_doppioni(ele);
  52.        stampa_dati(ele);
  53.  
  54.   readln;
  55. end.


Ultima modifica effettuata da Tommaso95 il 17/10/2012 alle 20:18
PM Quote
Avatar
Poggi Marco (Member)
Guru


Messaggi: 969
Iscritto: 05/01/2010

Segnala al moderatore
Postato alle 21:46
Mercoledì, 17/10/2012
1) Prima di inizializzare pos, devi racchiudere il ciclo for tra un begin e un end, altrimenti verrà assegnato 1 a pos per cento volte, e successivamente eseguito il ciclo repeat una volta.

Ad esempio:
Codice sorgente - presumibilmente Delphi

  1. procedure controllo_doppioni(var ele:tab);
  2.      var a,pos:byte;
  3. begin
  4.       a:=1;
  5.       while a<100 do
  6.       begin
  7.            pos:=a+1; // inizializzo pos all' inizio del ciclo esterno
  8.            repeat
  9.                if (ele[a]<>ele[pos]) or (pos=a) then // mi accerto che gli indici siano diversi
  10.                begin
  11.                    pos:=pos+1;
  12.                end
  13.                else
  14.                begin
  15.                    ele[pos]:=random(100)+1;
  16.                    pos:=2;
  17.                    a:=1;
  18.                end;
  19.            until  pos>100;
  20.            a:=a+1;
  21.       end;
  22. end;



2) La funzione stampa funziona comunque con var o senza, perché in entrambi i casi riceve i valori del vettore; cambia solo la modalità di ricezione.

Prova a togliere var da controllo_doppioni, e richiamare le funzioni nel seguente modo:
Codice sorgente - presumibilmente Pascal

  1. begin
  2.   clrScr;
  3.   carica_dati(ele);
  4.   writeln('Vettore originale ');
  5.   stampa_dati(ele);
  6.   writeln;
  7.   controllo_doppioni(ele);
  8.   writeln('Eliminazione dei doppi ');
  9.   stampa_dati(ele);
  10.   readln;
  11. end.


PM Quote
Avatar
Tommaso95 (Normal User)
Newbie


Messaggi: 17
Iscritto: 17/10/2012

Segnala al moderatore
Postato alle 23:24
Mercoledì, 17/10/2012
Grazie, ho capito quasi tutto. Solo due domande:

1) Perchè metti (pos=a)? In teoria non sono sempre diversi?
2) Perchè alla fine metti a:=a+1; ? A cosa si riferisce?

Grazie mille ancora per al tua disponibilità

PM Quote
Avatar
Goblin (Member)
Expert


Messaggi: 375
Iscritto: 02/02/2011

Segnala al moderatore
Postato alle 23:35
Mercoledì, 17/10/2012
Testo quotato

Postato originariamente da Tommaso95:
In pratica devo:
- Creare un array con 100 elementi
- Riempirlo con numeri da 1 a 100
- Controllare la presenza di eventuali doppioni e se ci sono sostituirli
- Stampare l'array.



Io voglio darti una soluzione alternativa nel caso in cui il punto 4 potrebbe essere interpretato come:
"evitare la presenza di doppioni nell'array"

costruiamo un array di comodo con dentro la serie di numeri da 1 a 100:
Codice sorgente - presumibilmente Pascal

  1. for x:= 1 to 100 do
  2.     aDummy[x] := x;



estraiamo 1 numero a caso andado a pescare nell'array di comodo il relativo valore e settiamo il valore dell'array di comodo a -1, nel caso in cui il valore dell'array di comodo è già a -1 vuol dire che il relativo valore è già stato estratto dunque ripetiamo l'estrazione
Codice sorgente - presumibilmente Delphi

  1. nciclo:=1;
  2.   While nCiclo<=100 do
  3.   begin
  4.     nEstratto :=  random(100)+1;
  5.     if aDummy[nEstratto] <> -1 then
  6.     begin
  7.       ele[nCiclo] := aDummy[nEstratto];
  8.       aDummy[nEstratto] := -1;
  9.       inc(nCiclo);
  10.     end;
  11.   end;



In questo modo i tempi si riducono drasticamente, da una stima fatta "al volo" si dovrebbero risparmiare circa 15-20000 cicli di estrazione


Ibis redibis non morieris in bello
PM Quote
Avatar
Poggi Marco (Member)
Guru


Messaggi: 969
Iscritto: 05/01/2010

Segnala al moderatore
Postato alle 0:48
Giovedì, 18/10/2012
@ Tommaso95:

1)In effetti, la condizione " pos=a " risulta superflua. E' stato un eccesso di controllo.
Me ne sono reso conto solo ora...

2) L' istruzione  " a := a+1 ; " serve ad incrementare l' indice del ciclo esterno; ho sostituito il ciclo for con un ciclo while per ragioni di stile. Mi sembrava poco elegante maneggiare direttamente la variabile gestita dal for.

@ Goblin:

Esiste un metodo ancora più efficiente:

- Creo un vettore con tutti gli elementi che compaiono solo una volta.
  ( tutti i numeri da 1 a 100 in ordine crescente )

- Imposto in ciclo che esamini ogni posizione del vettore.

- Estraggo un numero casuale tra l' indice del ciclo ed il numero di elementi del vettore.

- Scambio i valori che si trovano in posizione dell' indice del ciclo e del numero estratto.

Ultima modifica effettuata da Poggi Marco il 18/10/2012 alle 0:50
PM Quote
Avatar
Tommaso95 (Normal User)
Newbie


Messaggi: 17
Iscritto: 17/10/2012

Segnala al moderatore
Postato alle 19:55
Giovedì, 18/10/2012
@ Goblin, Logicamente ho capito cosa vuoi fare, ma non ho ben capito cosa metti dentro aDummy e come fa ad essere uguale a -1.

@Marco Grazie ancora, ho capito perfettamente il programma adesso.
Se per caso hai già sotto mano il codice riguardante l'algoritmo di cui hai parlato, riusciresti a postarlo che non ho capito benissimo dalla descrizione? Se non hai il codice fa niente ;)

PM Quote
Avatar
Poggi Marco (Member)
Guru


Messaggi: 969
Iscritto: 05/01/2010

Segnala al moderatore
Postato alle 22:32
Giovedì, 18/10/2012
L' idea è impostare un ciclo che ad ogni iterazione, generi un numero sul vettore.

Quindi predispongo l' array
Codice sorgente - presumibilmente Delphi

  1. procedure precarica(var ele:tab; fine:integer);  (* fine è la dimensione del vettore *)
  2. var i:integer;
  3. begin
  4.  for i:=1 to fine do
  5.  begin
  6.    ele[i]:=i;
  7.  end;
  8. end;

Casualizzo il vettore:
Codice sorgente - presumibilmente Delphi

  1. procedure casualizza_vettore(var ele:tab; fine:integer);
  2. var i,estratto,scambio:integer;
  3. begin
  4.   precarica(ele, fine);
  5.   for i:=1 to fine-1 do
  6.   begin
  7.  
  8.     // genero un numero casuale che abbia un range uguale ai cicli ancora da effettuare, e parta da i+1
  9.     estratto:=i+1+random(fine-i);
  10.  
  11.     // lavoro sulle posizioni del vettore
  12.     scambio:=ele[i];
  13.     ele[i]:=ele[estratto];
  14.     ele[estratto]:=scambio;
  15.  
  16.   end;
  17. end;


Ultima modifica effettuata da Poggi Marco il 18/10/2012 alle 22:35
PM Quote
Pagine: [ 1 2 ] Precedente | Prossimo