Liste

di il
11 risposte

Liste

Ho problemi con la funzione per eliminare gli elementi doppioni all'interno di una lista.
Ho provato inizialmente a semplificare il problema eliminando solo gli elementi uguali al primo elemento della lista:
PNodo Doppioni(PNodo *l){
PNodo q1,q2;

if(*l!=NULL){
q1=*l;
q2=q1->next;
while(q2!=NULL){
if(q1->info==q2->info){
q1->next=q2->next;
free(q2);
q2=q1->next;}
else q2=q2->next;
}
}
return *l;
}
ma il programma non funziona bene, non ho capito l'output cosa fa precisamente.
In seguito volevo aggiungere un secondo ciclo while per scorrere la lista e controllare tutti gli elementi

while(q1->next!=NULL)
while(q2!=NULL){
if(q1->info==q2->info){
q1->next=q2->next;
free(q2);
q2=q1->next;}
else q2=q2->next;
q1=q1->next;
}
ma cosi invece da proprio errore di segmentazione

Potete aiutarmi?

11 Risposte

  • Re: Liste

    PNodo è già definito come puntatore, giusto? Allora devi usare l senza asterisco, altrimenti ti esce un puntatore a puntatore a nodo (che pure sarebbe comodo, se usato bene, per scorrere una lista).
    Se non sbaglio hai già una funzione per eliminare tutti gli elementi con un certo valore, prova a riciclare quella.
  • Re: Liste

    Avevo provato a utilizzare le funzioni
    PNodo Cancella(PNodo *l,int el); int Ricerca(PNodo l, int el);
    che un po' cambiato, ora anche Cancella ha un doppio puntatore, comunque funzionano.
    PNodo Doppioni(PNodo *l){
    PNodo tmp;
    tmp=(*l)->next;
    int val=(*l)->info;
    while(tmp->next!=NULL){
    if (Ricerca(tmp,val)>0)
    Cancella(&tmp,val);
    val=tmp->info;
    tmp=tmp->next;
    }
    return *l;}
    il problema è sempre la segmentazione ho provato anche con i singoli puntatori non penso siano loro il problema, credo che il programma non riesca a uscire dal ciclo ma non capisco il motivo.
    A volte, specialmente con liste corte, viene eseguito ma con un output parziale, simile al programma di inizio topic. Alcune cose vengon eliminate altre no
  • Re: Liste

    Puoi postare Cancella e Ricerca?
  • Re: Liste

    Ti sei accorto che stai utilizzando i tag QUOTE al posto dei tag CODE?

    Ti spiego un po' la situazione: correggere codice altrui, inteso come renderlo funzionante senza "snaturarlo" troppo (sempre che sia possibile farlo), non è affatto facile. Ciò richiede infatti di entrare nella logica dell'autore, capire da dove è partito e dove vuole arrivare. Ti renderai conto che oltre alla difficoltà intrinseca, soprattutto su argomenti del genere, il tutto richiede richiede molto tempo e voglia! Sinceramente per quanto mi riguarda manca sia l'uno che l'altra, quindi o aspetti qualche buon samaritano oppure potresti prendere in considerazione il consiglio che già ti ho dato anche nell'altro topic, ossia di scrivere codice più generico basato su funzioni che effettuano operazioni elementari. In questo modo non solo scriverai codice più chiaro e conciso, ma aumenterai notevolmente anche le probabilità di ricevere aiuto altrui.

    Detto questo, quello che farei è implementare le seguenti due funzioni:
    void elimina_nodo(nodo **p)
    finalizzata all'eliminazione di un generico nodo;
    nodo** trova(nodo **p, int info)
    finalizzata alla ricerca del primo nodo contenente info.

    A questo punto la funzione
    void cancella_elemento(nodo **p, int info)
    (che tu chiami Cancella()) può essere implementata utilizzando le suddette due funzioni con sole 2 righe di codice.
    Invece la funzione
    void cancella_doppioni(nodo **p)
    (che tu chiami Doppioni()) può essere implementata utilizzando la funzione cancella_elemento() con sole 3 righe di codice.

    Se decidi di seguire il mio consiglio e hai qualche dubbio, chiedi pure!
  • Re: Liste

    Scusa, Nippolo, la funzione trova non ha più senso che restituisca nodo*?
  • Re: Liste

    Magari per altri scopi può essere sufficiente il singolo puntatore, ma se vogliamo eliminare il nodo trovato attraverso la funzione elimina_nodo() (di cui ho riportato il prototipo), bisogna utilizzare il doppio puntatore.
  • Re: Liste

    Sono riuscito a fare funzionare il codice senza usare le due funzioni Cancella e Ricerca

    Alexv ha scritto:


    Puoi postare Cancella e Ricerca?
    Comunque eccole qui
    PNodo Cancella(PNodo *l, int el){
        PNodo q1, q2, tmp;
            while(*l!=NULL && (*l)->info==el){
            tmp=*l;
            *l=(*l)->next;
            free(tmp);}
    
        if(*l!=NULL){
    	q1=*l;
    	q2=q1->next;
    	while(q2 != NULL){
    		if(q2->info == el){
    			q1->next=q2->next;
    			free(q2);
                 q2=q1->next;
    		}
    		else{
    			q1=q2;
    			q2=q2->next;
    		}
    }}
    return *l;
            }
    int Ricerca(PNodo l, int el){
        int r=1;
        while(l != NULL && l->info != el){
        l=l->next;
        r++;
        }
        if(l != NULL && l->info==el)
        return r;
        else return -1;
    }
    magari riesci a capire perché non andava, ancora non me lo spiego. Grazie per l'aiuto di ieri!
  • Re: Liste

    Si può rendere più semplice una funzione con i puntatori doppi.
    
    PNodo Cancella(PNodo l, int el){
    	PNodo* p = &l;
        	PNodo tmp;
            while(*p !=NULL){
            	if( (*p)->info) == el){
            		tmp=*p;
            		*p=(*p)->next;
            		free(tmp);
            	}
            	else
            		p= &((*p)->next);
            }
     return l;
    }
    
    Se invece volevi passare PNodo *l alla funzione, avresti dovuto salvarti un puntatore al primo elemento da restituire alla fine, così:
    
    PNodo head = *l;
    l = &head;
    /* ciclo while su l */
    return head;
    
    Dopodiché, per ogni elemento della lista, chiami Cancella che elimina tutti i doppioni (a partire dal successivo)
    
    PNodo Doppioni(PNodo l){
    	PNodo* p = &l;
    	while( *p != NULL){
    		(*p)->next = Cancella((*p)->next, (*p)->info);
    		p = &((*p)->next);
    	}
    return l;
    }
    
    Edit: avevo mancato un return alla fine.
  • Re: Liste

    Gallhager ha scritto:


    Sono riuscito a fare funzionare il codice senza usare le due funzioni Cancella e Ricerca
    Male!

    Alexv ha scritto:


    Se invece volevi passare PNodo *l alla funzione, avresti dovuto salvarti un puntatore al primo elemento da restituire alla fine, così:
    In realtà se passi un puntatore doppio, la funzione può tranquillamente essere di tipo void.

    Cmq per la cronaca intendevo qualcosa del genere:
    void elimina_nodo(nodo **p)
    {
        if(*p)
        {
            nodo *temp = *p;
            *p = (*p)->next;
            free(temp);
        }
    }
    
    nodo** trova(nodo **p, int info)
    {
        while(*p && (*p)->data != info)
        {
            p = &(*p)->next;
        }
        return p;
    }
    
    void cancella_elemento(nodo **p, int info)
    {
        while(*(p = trova(p, info)))
        {
            elimina_nodo(p);
        }
    }
    
    void cancella_doppioni(nodo *p)
    {
        while(p)
        {
            cancella_elemento(&p->next, p->data);
            p = p->next;
        }
    }
  • Re: Liste

    Molto più carino, così .
    L'importante è non "rompere" l quando lo si passa per riferimento.
  • Re: Liste

    Alexv ha scritto:


    Molto più carino, così .
    L'idea è quella di scrivere codice efficiente e non ridondante!

    Alexv ha scritto:


    L'importante è non "rompere" l quando lo si passa per riferimento.
    Dipende, in alcuni casi la modifica è voluta. Prendi per esempio la funzione elimina_nodo() utilizzata per eliminare il primo nodo della lista.
Devi accedere o registrarti per scrivere nel forum
11 risposte