Eliminare un valore da array in c++

fortu1
ciao ragazzi sono nuova. vorrei un aiuto per un programma in c++.
questo programma deve ricevere in ingresso 2 vettori aventi lo stesso numeri di elementi.
bisogna calcolare:
-la media dei vettori
-il prodotto scalare tra i vettori
-eliminare dal vettore 1 gli elementi >= del rapporto tra il prodotto e la sua media.
Realizzare il programma implementando tali funzioni:
-leggi vett
-media
-prodotto scalare
-elimina
-stampa
Ho provato a farlo e mi trovo sia per il calcolo della media che per il calcolo del prodotto,ma mi elimina tutti i valori dal vettore e non capisco perchè.Dove sbaglio?
Ecco il programma aiutatemi grazie.



#include
#include

using namespace std;
void leggi_vett( int [],int &);
float media(int [], int &);
float prodotto( int [], int [],int &);
int elimina(int [],int &, float &);
void stampa(int [],int &);
const int DIM=100;

main () {
int n,i;
int V1[DIM];
int V2[DIM];
float m1,m2;
float ris;
float k;
float ris1,ris2,ris3;
cout <<"\n valore di n";
cin >>n;
cout << "\n primo vettore";
leggi_vett(V1,n);
cout<< "\n secondo vettore";
leggi_vett(V2,n);
cout <<"\n media del primo vettore ";
ris1=media(V1,n);
cout << ris1;
cout <<"\n media del secondo vettore ";
ris2=media(V2,n);
cout < cout <<" \n prodotto scalare tra i due vettori";
ris=prodotto(V1,V2,n);
cout < cout <<"\n eliminazione degli elementi dal primo vettore ";
k=ris/ris1;
cout <<" \n valore di k ";
cout < elimina(V1,n,k);
cout<<"\n nuovo vettore V1 ";
stampa(V1,n);
system ("PAUSE");
return 0;
}


void leggi_vett( int V[],int &n){

for (int i=0; i { cout<<"\n elemento di posizione "< cin >> V;}
}

float media(int V[], int &n){

int i;
float m;
float s=0;
for(i=0;i s=s+V;
m=s/n;
return m;}

float prodotto( int V1[], int V2[], int & n) {
int V[DIM];
int p=0;
for (int i=0; i {V=V1*V2;
p=p+V;}
return p; }

int elimina(int V1[],int & n, float & k){
int cont=0;
int i,j;
for ( i=0;i { if (V1>=k)
for ( j=i;j V1[j]=V1[j+1];
n--;
cont++;
i--;}

return cont;}

void stampa(int V[],int &n){
for (int i=0;i {cout <<"\n elemeno di posizione " < cout << V;}
}

Risposte
Umby2
Hai controllato il valore di k se è corretto prima di entrare nella routine "elimina" ?

Noto che hai preferito traslare di una posizione tutti gli elementi del vettore, non sarebbe stato piu semplice prendere l'ultimo elemento del vettore e posizionarlo nel posto da eliminare ?

fortu1
il valore di k l'ho controllato ed è giusto.
Riguardo al tuo suggerimento non ho ben capito.
Se io ho due vettori es: 6 ,2 ,1
1,1,1
la media del primo è 3, quella del secondo è 1
il prodotto scalare è 9
i valori da eliminare sono quelli >= 9/3=3
dovrei ottenere alla fine il vettore 2,1; quindi non è l'ultimo elemento del vettore che si va a posizionare al posto di quello eliminato ma il suo successivo, che non è detto sia l'ultimo del vettore.

Rggb1
Noto che
int elimina(int V1[],int & n, float & k){
int cont=0;
int i,j;
for ( i=0;i<n;i++)
{ if (V1[i]>=k)
for ( j=i;j<n;j++)
V1[j]=V1[j+1];
n--;
cont++;
i--;}

return cont;} 

per tutti gli n elementi a partire da 0 esegue le istruzioni
n--; //decrementa n
cont++; //incrementa cont
i--;//decrementa i
quindi c'è sicuramente qualcosa di sbagliato, riesci a vedere cosa?

PS. Come mai usi sempre parametri passati per riferimento?

@Umby
Giusta l'osservazione in merito all'eliminazione tramite scambio con l'ultimo elemento, ma in senso stretto poiché i vettori (1,2) e (2,1) non sono uguali, magari la soluzione può non essere accettabile..

Umby2
"Rggb":


@Umby
Giusta l'osservazione in merito all'eliminazione tramite scambio con l'ultimo elemento, ma in senso stretto poiché i vettori (1,2) e (2,1) non sono uguali, magari la soluzione può non essere accettabile..


Nel caso in cui i vettori siano ordinati, ovvero bisogna comunque rispettare la sequenza dei vari caratteri all'interno del vettore, son d'accordo con te.
Pero' il testo non mi sembrava che "limitasse" di questa condizione, ecco perchè avevo proposto quella sostituzione.

Umby2
"fortu":


int elimina(int V1[],int & n, float & k){
int cont=0;
int i,j;
for ( i=0;i { if (V1>=k)
for ( j=i;j V1[j]=V1[j+1];
n--;
cont++;
i--;}

return cont;}



I 2 cicli mi sembrano corretti.... ma per caso, ci manca una parentesi ?
Consiglio anche a te di allineare l'inizio e la fine di una condizione. E' importante anche per chi legge il codice, e tenta di capirlo. :roll:

Rggb1
"Umby":
Nel caso in cui i vettori siano ordinati, ovvero bisogna comunque rispettare la sequenza dei vari caratteri all'interno del vettore, son d'accordo con te.
Pero' il testo non mi sembrava che "limitasse" di questa condizione, ecco perchè avevo proposto quella sostituzione.

Hai ragione, c'è un problema di comprensione del testo: si parla di programmi, e tradizionalmente il termine vettore==array; si parla di prodotto scalare e media, e il termine vettore==elemento di spazio vettoriale.

@fortu
Torno al problema: come fa notare anche Umby
"Umby":
I 2 cicli mi sembrano corretti.... ma per caso, ci manca una parentesi ?

ti basta aggiungere un livello di parentesi e dovresti essere a posto.
Per farti capire meglio ti "riscrivo" la tua funzione, semplicemente allineando il codice:
int elimina(int V1[],int & n, float & k){
  int cont=0;
  int i,j;
  for ( i=0;i<n;i++) {
    if (V1[i]>=k) for ( j=i;j<n;j++) V1[j]=V1[j+1];
    n--;
    cont++;
    i--;
  }
  return cont;
}

E l'errore "salta all'occhio". Va beh, magari c'eri già arrivata.
Consiglio anche a te di allineare l'inizio e la fine di una condizione.

Consiglio utilissimo: se l'avessi fatto, ti saresti accorta subito del problema ;)

fortu1
si ragazzi grazie dell'aiuto, mi ero accorta che l'errore era della parentesi!!!!
siete stati gentilissimi. :D

Umby2
if (V1>=k) for ( j=i;jV1[j+1];

non è che ti possa dare noie anche questo [j+1] ? :!:

apatriarca
Ciao e benvenuta nel forum. Ci sono due importanti considerazioni stilistiche da fare prima di vedere la correzione del codice:
1. il codice andrebbe inserito all'interno dell'apposito tag [ code ] (che si può inserire manualmente oppure premendo sull'apposito pulsante) quando inserito nel forum;
2. il codice andrebbe formattato in modo da facilitarne la lettura e comprensione.

Partirei dalla parte dell'esercizio con la quale hai maggiori difficoltà. L’eliminazione degli elementi di un array che non soddisfano una certa proprietà è un operazione abbastanza comune e vale quindi la pena di imparare a farlo bene una volta per tutte. Se ho capito bene l’algoritmo che hai in mente, ogni volta che vuoi eliminare un elemento sposti tutti gli elementi successivi di una posizione. È corretto ma inutilmente inefficiente. Ha infatti complessità $O(n^2)$. Seguendo il tuo algoritmo, un qualsiasi elemento che soddisfa la proprietà passa per tutte le posizioni intermedie tra la posizione iniziale e quella finale. Sarebbe meglio trovare un metodo per stabilire direttamente la posizione finale dallo stato degli elementi precedenti. Considera un qualsiasi indice $k$ e supponi di aver verificato la condizione per tutti gli elementi precedenti. Se $s$ è il numero di elementi che ha superato il test, allora l'elemento all'indice $k$ sarà preceduto da $s$ elementi nell'array finale e quindi $s$ è l'indice di destinazione dell'elemento in posizione $k$. Il “trucco” per risolvere il problema con complessità lineare è quindi semplicemente quello di memorizzare il numero di elementi che hanno passato il test. Il codice sarà quindi:
int elimina (int v[], int n, float k)
{
    int cont = 0;
    
    for (int i = 0; i < n; ++i) {
        if (v[i] >= k) {
            v[cont] = v[i];
            ++cont; 
        }
    }

    return cont;
}

Ho fatto qualche modifica alla logica della funzione della quale ne discuterò in seguito. Vorrei invece tornare alla tua funzione e vedere quali sono gli errori che hai commesso. Il primo errore è quello che ti è già stato fatto notare della parentesi e il secondo riguarda gli indici. $j$ assume infatti tutti i valori da $i$ a $n-1$ e quindi $j+1$ assume anche il valore $n$ che è oltre i limiti dell'array. Devi quindi cambiare la condizione del codice in modo da fermarsi a $n-2$ (devi cioè scrivere $j < (n-1)$).

Passiamo quindi alla funzione prodotto. Il risultato è corretto ma ci sono alcune parti del codice che non credo abbiano molto senso. Non c'è in particolare alcun motivo di usare un vettore ausiliario che contenga il prodotto di V1 e V2. Sarebbe stato infatti sufficiente scrivere:
int prodotto(int v1[], int v2[], int n)
{
    int p = 0;
    for (int i = 0; i < n; ++i) {
        p += v1[i] * v2[i];
    }
    return p;
} 


Veniamo quindi a commenti un po’ più stilistici:
1. Anche se la libreria è ancora accessibile in C++, si preferisce attualmente includere la libreria . Le due librerie sono uguali, ma le funzioni della seconda vengono inserite nel namespace std, mentre quelle della prima nel namespace globale.
2. La funzione main deve essere definita in uno dei seguenti modi (o equivalenti):
int main()
int main(int argc, char **argv)

Devi cioè in particolare inserire come valore di ritorno int.
3. In C++ si possono definire le variabili in qualsiasi parte della funzione. È normalmente più leggibile farlo subito prima dell'uso in modo da non avere un enorme elenco di variabili all'inizio come nel tuo codice.
4. I nomi in maiuscolo sono normalmente utilizzati solo per le costanti e quindi sarebbe meglio non usare lettere maiuscole per i due vettori.
5. system("PAUSE"); non è portabile e funziona solo su sistemi Windows.
6. return 0; può essere omesso alla fine della funzione main.
7. Stai passando tutte le dimensioni come reference ma sarebbe meglio non farlo. In questo modo costringi infatti l'utente della tua funzione ad usare una variabile, ma in alcuni casi una costante potrebbe andare bene lo stesso. Inoltre non ha senso, per la maggior parte delle tue funzioni, modificare la dimensione dell'array. L'unica funzione in cui può aver senso passare la dimensione come reference è quella che elimina gli elementi, ma nel codice che ti ho scritto ho deciso di non farlo.

fortu1
grazie apatriarca,
ho corretto la condizione del codice e grazie mille per tutte le tue delucidazioni :P

fortu1
ciao ragazzi, ho un problma con un altro programma;premetto che è da poco che sto imparando a fare qualche programmino e non sono molto ferrata in queste cose.
Tornando al programma mi si chiede di:
inserire un vettore , eiminare i valori doppioni, indicare il numero di valori eliminati e stampare il nuovo vettore.
es:
se ho il vettore:
2 3 4 3 7 3 2 9
devo ottenere:
2 3 4 7 9

Ho provato a scrivere il programma ma non va


#include<iostream>
#include<stdlib.h>

using namespace std;

void leggi_vett(int [] ,int &);
int elimina_uguali( int [], int &);
void stampa( const int [], const int &);
const int DIM=100;


int main () {
     int ris;
     int n;
     int V[DIM];
     cout <<"\n procedura di inserimento del vettore";
     cout <<"\n scegliere il valore della lunghezza del vettore";
     cin >>n;
     cout <<"\n inserire i valori del vettore";
     leggi_vett(V,n);
     cout<<"\n eliminazione dei valori uguali";
     ris=elimina_uguali(V,n);
     cout<<"\n valori elmiminati"<< ris;
     stampa(V,n);

 system ("PAUSE");
}


void leggi_vett ( int v[], int & n) 
 {    for (int i=0; i<n; i++)
    { cout <<"\n elemento  di posizione " <<i << ": ";
     cin >>v[i];
     }
 }  
  

int elimina_uguali(int v[], int & n)
{  int cont=0;
    for (int i=0;i<n;i++) 
   { for (int j=i+1;j<n;j++)
      if (v[i]=v[j])
      {for(int k=j;k<n-1;k++)
         v[k]=v[k+1];
         j--;
         n--;
         cont++; 
        }
        return cont;
     }

}    
void stampa(const int v[], const int &n) 
 {     for (int i=0; i<n;i++)
       {cout<< "\n nuovo vettore";
      cout <<v[i];
      }
 }

Omega1
Ciao!

Ho letto il tuo programme, e ho trovato alcuni errori:

1) Nella funzione int main(), la dichiari appunto int, ma alla fine manca l' istruzione " return 0; ".

2) Nella funzione " int elimina_uguali( int v[ ], int & n) " dichiari " if (v[ i ] = v[ j ] ) ", ti ricordo che in c il simbolo = si usa per l' assegnamento. Per confrontare l' uguaglianza si usa il simbolo ==.

3) Sempre nella funzione " int elimina_uguali( int v[ ], int & n ) " metti " return cont; " all' interno di un ciclo for.

Ecco il codice corretto:

#include<iostream>

using namespace std;

void leggi_vett(int [] ,int &);
int elimina_uguali( int [], int &);
void stampa( const int [], const int &);
void trasla(int [], const int &, int &);
const int DIM=100;


int main (int argv, char *argc[])
{
     int ris;
     int n;
     int V[DIM];
     cout <<"\nProcedura di inserimento del vettore";
     cout <<"\nscegliere il valore della lunghezza del vettore ";
     cin >>n;
     cout <<"\n inserire i valori del vettore ";
     leggi_vett(V, n);
     cout<<"\n eliminazione dei valori uguali";
     ris=elimina_uguali(V,n);
     cout<<"\n valori elmiminati: "<<ris;
     stampa(V,n);
     fflush(stdin);
     getchar();
     return 0;
}


void leggi_vett ( int v[], int & n)
 {
    for (int i=0; i<n; i++)
    {
     cout <<"\nelemento  di posizione " <<i+1<< ": ";
     cin >>v[i];
    }
 }


int elimina_uguali(int v[], int & n)
{
    int cont=0;
    for (int i=0; i<n; i++)
    {
      for (int j=i+1; j<n; j++)
        if (v[i]==v[j])
        {
            trasla(v, j, n);
            cont++;
        }
    }
     return cont;
}

void trasla(int v[], const int &inizio, int &fine)
{
     int i=0;
     for (i=inizio; i<fine; i++) v[i]=v[i+1];
     fine--;
}

void stampa(const int v[], const int &n)
 {
     cout<<"\n\nNuovo vettore:\n";
     for (int i=0; i<n;i++) cout<< "\n Elemento "<<i+1<<" :\t"<<v[i];
 }


apatriarca
"Omega":

1) Nella funzione int main(), la dichiari appinto int, ma alla fine manca l' istruzione " return 0; ".

In C++, l'istruzione "return 0;" alla fine del main è facoltativa. Leggi per esempio qui. È principalmente una questione stilistica.[/url]

Omega1

Omega ha scritto:

1) Nella funzione int main(), la dichiari appinto int, ma alla fine manca l' istruzione " return 0; ".


In C++, l'istruzione "return 0;" alla fine del main è facoltativa. Leggi per esempio qui. È principalmente una questione stilistica.[/url]


Su tutti i manuali ho sempre letto che, alla fine di un programma, ci vuole sempre l' istruzione " return 0; ".

Comunque grazie per l'avviso!

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.