RISOLTO C++ : Problema rimuovendo il primo elemento da linked list

Marcus Aseth

Utente Attivo
404
138
OS
Windows 10
Ciao gente, stato facendo un esercizio sulla creazione di linked list e rimozione di un elemento all'interno di essa. Tutto funziona e riesco a rimuovere gli elementi con l'apposita funzione "Remove Element" TRANNE che se provo a rimuovere il primo elemento della lista, nel codice sotto sarebbe il numero 10 "RemoveElement(NumberList, 10);"
Sospetto che il problema stia nel fatto che la funzione RemoveElement( ) prenda l'argument List come pointer to reference, e quando all'interno della funzione modifico dove punta il NumberList con le righe:

Codice:
NumberList = p_current->p_next;
delete p_current;

non sto di fatto modificando il NumberList usato come argument nella chiamata alla funzione. Infatti il crash penso sia dovuto al fatto che quando eseguo il codice e faccio cout della List, il primo elemento della mia list cerca ancora di accedere all'address che ho "rilasciato" (tramite delete) nel codice sopra.
E' quello il problema, giusto?
E se si, come faccio a far sì che il codice sopra faccia quello che voglio io, ovvero far si che il pointer al primo elemento della mia List punti al secondo elemento nel caso il primo dovesse venire rimosso?



Codice:
#include <iostream>
using namespace std;


struct Number
{
    int Num = 0;
    Number* p_next = NULL;
};


Number* AddElement(Number* NumberList)
{
    Number* p_new_num = new Number;
    p_new_num->Num = NumberList->Num + 1;
    p_new_num->p_next = NumberList;
    return p_new_num;
}


void RemoveElement(Number *& NumberList,int n)
{
    Number* p_current = NumberList;
    Number* p_previous_temp = NULL;


    //While not at the end of the list
    while (p_current != NULL)
    {
        //If we found the element that need to be removed from list
        if (p_current->Num == n)
        {
            //If we are at the first element in the list
            if (p_previous_temp == NULL)
            {
                //List now has a new first element
                NumberList = p_current->p_next;
                delete p_current;
                return;
            }
            //Every other element that is not the first one
            else
            {
                p_previous_temp->p_next = p_current->p_next;
                delete p_current;
                return;
            }
        }
        //Advance the two pointers 
        p_previous_temp = p_current;
        p_current = p_current->p_next;
    }
}


int main()
{
    Number* NumberList = new Number;


    for (int i = 0; i < 10; i++)
    {
        NumberList = AddElement(NumberList);
    }


    Number* p_temp = NumberList;


    RemoveElement(NumberList, 5);
    RemoveElement(NumberList, 3);
    RemoveElement(NumberList, 7);
    RemoveElement(NumberList, 9);
    RemoveElement(NumberList, 10);


    while (p_temp != NULL)
    {
        cout << p_temp->Num << " ";
        p_temp = p_temp->p_next;
    }
}
 

rodhellas

Utente Èlite
1,522
427
CPU
Ryzen 5 3600
Dissipatore
GELID Phantom
Scheda Madre
MSI B450 Gaming Plus Max
HDD
500GB m.2 + 2TB HDD
RAM
16GB Corsair LPX 3000mhz
GPU
Gigabyte GTX 960 OC
Audio
Integrata
Monitor
SyncMaster 223BW
PSU
Antec HCG-520M
Case
Meshify C
Net
Gigabit Fastweb
OS
Windows 10 64bit
Ciao gente, stato facendo un esercizio sulla creazione di linked list e rimozione di un elemento all'interno di essa. Tutto funziona e riesco a rimuovere gli elementi con l'apposita funzione "Remove Element" TRANNE che se provo a rimuovere il primo elemento della lista, nel codice sotto sarebbe il numero 10 "RemoveElement(NumberList, 10);"
Sospetto che il problema stia nel fatto che la funzione RemoveElement( ) prenda l'argument List come pointer to reference, e quando all'interno della funzione modifico dove punta il NumberList con le righe:

Codice:
NumberList = p_current->p_next;
delete p_current;

non sto di fatto modificando il NumberList usato come argument nella chiamata alla funzione. Infatti il crash penso sia dovuto al fatto che quando eseguo il codice e faccio cout della List, il primo elemento della mia list cerca ancora di accedere all'address che ho "rilasciato" (tramite delete) nel codice sopra.
E' quello il problema, giusto?
E se si, come faccio a far sì che il codice sopra faccia quello che voglio io, ovvero far si che il pointer al primo elemento della mia List punti al secondo elemento nel caso il primo dovesse venire rimosso?



Codice:
#include <iostream>
using namespace std;


struct Number
{
    int Num = 0;
    Number* p_next = NULL;
};


Number* AddElement(Number* NumberList)
{
    Number* p_new_num = new Number;
    p_new_num->Num = NumberList->Num + 1;
    p_new_num->p_next = NumberList;
    return p_new_num;
}


void RemoveElement(Number *& NumberList,int n)
{
    Number* p_current = NumberList;
    Number* p_previous_temp = NULL;


    //While not at the end of the list
    while (p_current != NULL)
    {
        //If we found the element that need to be removed from list
        if (p_current->Num == n)
        {
            //If we are at the first element in the list
            if (p_previous_temp == NULL)
            {
                //List now has a new first element
                NumberList = p_current->p_next;
                delete p_current;
                return;
            }
            //Every other element that is not the first one
            else
            {
                p_previous_temp->p_next = p_current->p_next;
                delete p_current;
                return;
            }
        }
        //Advance the two pointers 
        p_previous_temp = p_current;
        p_current = p_current->p_next;
    }
}


int main()
{
    Number* NumberList = new Number;


    for (int i = 0; i < 10; i++)
    {
        NumberList = AddElement(NumberList);
    }


    Number* p_temp = NumberList;


    RemoveElement(NumberList, 5);
    RemoveElement(NumberList, 3);
    RemoveElement(NumberList, 7);
    RemoveElement(NumberList, 9);
    RemoveElement(NumberList, 10);


    while (p_temp != NULL)
    {
        cout << p_temp->Num << " ";
        p_temp = p_temp->p_next;
    }
}

Codice:
p_current = p_current->p_next;
NumberList->Num = p_current->Num;
NumberList->p_next = p_current->p_next;
delete p_current;
return;

Spero che la sintassi sia giusta e che sia giusto in se( mai usato c++ ma solo c :asd: ). Sposti current al nodo successivo, copi il valore di Num al posto del valore della tua testa, punti la tua testa al nodo successivo di current e dopo puoi cancellarlo tranquillamente (spero si capisca :asd:. ). L'output è il seguente: 8 6 4 2 1 0
 
Ultima modifica:

Marcus Aseth

Utente Attivo
404
138
OS
Windows 10
Codice:
Number* p_temp;
Number* p_current = NumberList;


p_temp = p_current->p_next;
NumberList->Num = p_temp->Num;
NumberList->p_next = p_temp;
delete p_current;

Spero che la sintassi sia giusta e che sia giusto in se( mai usato c++ ma solo c :asd: ). Comunque crei un puntatore ausiliario e lo fai puntare al secondo elemento della lista. Fai puntate la testa (Numberlist) al puntatore ausiliario e quindi puoi cancellare tranquillamente il primo valore (ovvero p_current).

- - - Updated - - -

Ho provato a compilare, come risultato mi dà 8 8 6 4 2 1 0. Domanda, lo 0 alla fine è voluto?

Ma appunto è quello che avevo fatto nel primo reply, nelle righe:

Codice:
NumberList = p_current->p_next;
delete p_current;
return;

A meno che non mi sfugga qualcosa, p_current era il mio puntatore ausiliario.
però non è la soluzione corretta, il punto è rimuovere il 10 e far puntare la testa della lista all'8, ma adesso tu ti ritrovi con due 8 :lol:
L'output final che voglio ottenere è " 8 6 4 2 1 0 "
Bhe,probabilmente fà ad arrivarci in 2 step rimuovendo succesivamente il penultimo elemento, quindi mi pare una mezza soluzione :sisilui:
Non c'è un modo piu "diretto" in quella funzione per spostare il pointer NumberList al secondo elemento e rimuovere la prima variabile della lista?

side note: rileggendo meglio ho notato ora che non hai mai cambiato a cosa NumberList punta, percui ne hai soltanto modificato i valori interni
Io voglio proprio puntare NumberList su un'altra variabile
 
Ultima modifica:

rodhellas

Utente Èlite
1,522
427
CPU
Ryzen 5 3600
Dissipatore
GELID Phantom
Scheda Madre
MSI B450 Gaming Plus Max
HDD
500GB m.2 + 2TB HDD
RAM
16GB Corsair LPX 3000mhz
GPU
Gigabyte GTX 960 OC
Audio
Integrata
Monitor
SyncMaster 223BW
PSU
Antec HCG-520M
Case
Meshify C
Net
Gigabit Fastweb
OS
Windows 10 64bit
Ma appunto è quello che avevo fatto nel primo reply, nelle righe:

Codice:
NumberList = p_current->p_next;
delete p_current;
return;

A meno che non mi sfugga qualcosa, p_current era il mio puntatore ausiliario.
però non è la soluzione corretta, il punto è rimuovere il 10 e far puntare la testa della lista all'8, ma adesso tu ti ritrovi con due 8 :lol:
L'output final che voglio ottenere è " 8 6 4 2 1 0 "
Bhe,probabilmente fà ad arrivarci in 2 step rimuovendo succesivamente il penultimo elemento, quindi mi pare una mezza soluzione :sisilui:
Non c'è un modo piu "diretto" in quella funzione per spostare il pointer NumberList al secondo elemento e rimuovere la prima variabile della lista?
Non ho fatto in tempo a modificare il messaggio, comunque ora ho sistemato e dovrebbe darti il risultato corretto :rock:

Codice:
p_current = p_current->p_next;
NumberList->Num = p_current->Num;
NumberList->p_next = p_current->p_next;
delete p_current;
return;
 

Marcus Aseth

Utente Attivo
404
138
OS
Windows 10
Non ho fatto in tempo a modificare il messaggio, comunque ora ho sistemato e dovrebbe darti il risultato corretto :rock:

Codice:
p_current = p_current->p_next;
NumberList->Num = p_current->Num;
NumberList->p_next = p_current->p_next;
delete p_current;
return;

Si il risultato finale probabilmente è corretto, però stai facendo operazioni di copia e sostituzione.
Io voglio puntare NumberList al secondo elemento senza dover eseguire nessuna copia,cosa fattibilissima al di fuori di quella funzione, io voglio capire come farlo dentro la funzione :)
 
Ultima modifica:

1nd33d

Utente Attivo
653
279
CPU
Intel i5 3570K @ 4,5Ghz
Dissipatore
Scythe Mugen 2
Scheda Madre
Gigabyte Z77X-UD3H
HDD
Samsung 840 PRO 256GB + Sandisk Ultra 250GB + Sandisk Plus 960GB
RAM
2x8GB Crucial Ballistix Tactical @2000Mhz CL9
GPU
XFX RX480 GTR Black Edition
Audio
Auzentech X-Fi Forte
Monitor
AOC i2369VW
PSU
Seasonic P660
Case
eh?
Periferiche
Razer Naga HEX v2
OS
Windows 10 64bit - Linux Mint 18
Non ho letto tutti post ma penso di aver capito il problema.
Una possibile soluzione è in realtà piuttosto banale: potresti usare il primo elemento della lista come "segnaposto".
In pratica la lista vuota avrà comunque un elemento, il primo, che però nelle tue funzioni non sarà considerato come elemento. In questo modo, quando andrai a eliminare il primo elemento della lista, in realtà andrai a eliminare il secondo elemento della struttura e non perderai mai il riferimento iniziale.
Una alternativa più "raffinata", è usare due strutture: una come descrittore, che sarà per esempio di tipo "numberlist" e un'altra struttura solo per contenere i dati (la struttura che hai già definito).
 

rodhellas

Utente Èlite
1,522
427
CPU
Ryzen 5 3600
Dissipatore
GELID Phantom
Scheda Madre
MSI B450 Gaming Plus Max
HDD
500GB m.2 + 2TB HDD
RAM
16GB Corsair LPX 3000mhz
GPU
Gigabyte GTX 960 OC
Audio
Integrata
Monitor
SyncMaster 223BW
PSU
Antec HCG-520M
Case
Meshify C
Net
Gigabit Fastweb
OS
Windows 10 64bit
Ciao gente, stato facendo un esercizio sulla creazione di linked list e rimozione di un elemento all'interno di essa. Tutto funziona e riesco a rimuovere gli elementi con l'apposita funzione "Remove Element" TRANNE che se provo a rimuovere il primo elemento della lista, nel codice sotto sarebbe il numero 10 "RemoveElement(NumberList, 10);"
Sospetto che il problema stia nel fatto che la funzione RemoveElement( ) prenda l'argument List come pointer to reference, e quando all'interno della funzione modifico dove punta il NumberList con le righe:

Codice:
NumberList = p_current->p_next;
delete p_current;

non sto di fatto modificando il NumberList usato come argument nella chiamata alla funzione. Infatti il crash penso sia dovuto al fatto che quando eseguo il codice e faccio cout della List, il primo elemento della mia list cerca ancora di accedere all'address che ho "rilasciato" (tramite delete) nel codice sopra.
E' quello il problema, giusto?
E se si, come faccio a far sì che il codice sopra faccia quello che voglio io, ovvero far si che il pointer al primo elemento della mia List punti al secondo elemento nel caso il primo dovesse venire rimosso?



Codice:
#include <iostream>
using namespace std;


struct Number
{
    int Num = 0;
    Number* p_next = NULL;
};


Number* AddElement(Number* NumberList)
{
    Number* p_new_num = new Number;
    p_new_num->Num = NumberList->Num + 1;
    p_new_num->p_next = NumberList;
    return p_new_num;
}


void RemoveElement(Number *& NumberList,int n)
{
    Number* p_current = NumberList;
    Number* p_previous_temp = NULL;


    //While not at the end of the list
    while (p_current != NULL)
    {
        //If we found the element that need to be removed from list
        if (p_current->Num == n)
        {
            //If we are at the first element in the list
            if (p_previous_temp == NULL)
            {
                //List now has a new first element
                NumberList = p_current->p_next;
                delete p_current;
                return;
            }
            //Every other element that is not the first one
            else
            {
                p_previous_temp->p_next = p_current->p_next;
                delete p_current;
                return;
            }
        }
        //Advance the two pointers 
        p_previous_temp = p_current;
        p_current = p_current->p_next;
    }
}


int main()
{
    Number* NumberList = new Number;


    for (int i = 0; i < 10; i++)
    {
        NumberList = AddElement(NumberList);
    }


    Number* p_temp = NumberList;


    RemoveElement(NumberList, 5);
    RemoveElement(NumberList, 3);
    RemoveElement(NumberList, 7);
    RemoveElement(NumberList, 9);
    RemoveElement(NumberList, 10);


    while (p_temp != NULL)
    {
        cout << p_temp->Num << " ";
        p_temp = p_temp->p_next;
    }
}
Credo di aver risolto (senza toccare il tuo codice), il problema stava con
Codice:
Number* p_temp = NumberList;
, avendolo messo prima degli elementi da cancellare, lui ti stampava comunque la lista originale ( p_temp ti puntava comunque al primo elemento che avevi cancellato ). Ti basta metterlo dopo i vari RemoveElement e ti viene giusto! :asd:
 
  • Mi piace
Reazioni: Marcus Aseth

Marcus Aseth

Utente Attivo
404
138
OS
Windows 10
Credo di aver risolto (senza toccare il tuo codice), il problema stava con
Codice:
Number* p_temp = NumberList;
, avendolo messo prima degli elementi da cancellare, lui ti stampava comunque la lista originale ( p_temp ti puntava comunque al primo elemento che avevi cancellato ). Ti basta metterlo dopo i vari RemoveElement e ti viene giusto! :asd:


:cav:
Ecco perchè leggo sempre di dichiarare le variabili PRIMA di usarle e non millemila righe sopra... :hihi:

Grazie mille :party:
 
  • Mi piace
Reazioni: rodhellas

Ci sono discussioni simili a riguardo, dai un'occhiata!

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!

Discussioni Simili