Domanda classe sequenza con lista a puntatori

Stato
Discussione chiusa ad ulteriori risposte.

Zast

Utente Bronze
21 Novembre 2016
11
5
0
28
Ultima modifica da un moderatore:
Salve a tutti, non riesco a fare un esercizio assegnatomi.
L'esercizio riguarda l'implementazione di una classe sequenza con una lista a puntatori.
La classe deve avere le seguenti caratteristiche:
Le variabili private sono: un cursore, che mantiene l'elemento attuale, un precursore, che mantiene l'elemento prima di quello attuale, una testa ed una coda.
La classe lista e le implementazioni delle sue funzioni le ho prese dal libro che mi ha proposto l'esercizio.
Ecco i seguenti files.
Faccio notare che non ho usato nè ereditarietà nè polimorfismo, poichè il prof non li ha trattati ancora.
Il mio problema è che quando provo a stampare la lista, stampa solo il primo elemento e non riesco a capire proprio perchè.
L'errore si trova quasi sicuramente nella funzione "inserisci dopo", (dopo si intende 'dopo il cursore').
Ho provato in molti altri modi ma niente da fare
f33.gif
e ci sto sbattendo la testa da due giorni
f30.gif
.

Header file della lista:

C++:
class nodo{

public:
typedef int value_type;
typedef std::size_t size_type;

//COSTRUTTORI E DISTRUTTORE
nodo(const value_type& dato_iniziale, nodo* link_iniziale){ dato=dato_iniziale; next=link_iniziale;};

//FUNZIONI MEMBRO NON COSTANTI
void set_dato(const value_type nuovo_dato){dato=nuovo_dato;};
void set_link(nodo* nuovo_link){next=nuovo_link;};

//FUNZIONI MEMBRO COSTANTI

value_type valore() const {return dato;};
nodo* link() const {return next;};
bool empty() const {return next==0;};


private:
value_type dato;
nodo* next;

};


std::size_t lunghezza(const nodo* testa);
void inserisci_in_testa(nodo* &testa, const nodo::value_type& dato );
void inserisci(nodo* ptr_precedente, const nodo::value_type& dato);
void rimuovi_in_testa(nodo* &testa);
void rimuovi(nodo* &ptr_precedente);




File cpp della lista:

#include <iostream>
#include <cstdlib>
#include <cassert>
#include "nodoPersonalizzato.h"

using namespace std;


std::size_t lunghezza(const nodo* testa){

const nodo* cursore;
size_t dimensione=0;

for(cursore=testa; cursore!=NULL; cursore=cursore->link()){
dimensione++;
}
return dimensione;
}

void inserisci_in_testa( nodo* &testa, const nodo::value_type& dato){

testa=new nodo(dato, testa);
}


void inserisci( nodo* ptr_precedente, const nodo::value_type& dato){

nodo* ptr_inserito;
ptr_inserito=new nodo(dato, ptr_precedente->link());
ptr_precedente->set_link(ptr_inserito);
}

void rimuovi_in_testa(nodo* &testa){

nodo* ptr_rimuovi;
ptr_rimuovi=testa;
testa=testa->link();
delete ptr_rimuovi;

}


void rimuovi(nodo* ptr_precedente){

nodo* ptr_rimuovi;

ptr_rimuovi=ptr_precedente->link();
ptr_precedente->set_link(ptr_rimuovi->link());
delete ptr_rimuovi;

}


File header della sequenza:

class sequenza{

public:
// DICHIARAZIONE TYPEDEF
typedef int value_type;
typedef std::size_t size_type;

//COSTRUTTORI E DISTRUTTORE
sequenza(){num_nodi=0; testa=NULL; coda=testa; cursore=testa; precursore=testa;};

//VARIABILI MEMBRO NON CONSTANTI
void inizia(){cursore=testa;};
void avanza(){cursore=cursore->link();};
void inserisci_prima(const value_type &input);
void inserisci_dopo(const value_type &input);
void rimuovi_corrente();
void stampa_sequenza();

//VARIABILI MEMBRO COSTANTI
size_t dimensione() const {return (num_nodi);};
nodo* valore_corrente() const {return cursore;};

private:
size_type num_nodi;
nodo* testa;
nodo* coda;
nodo* cursore;
nodo* precursore;



};


File cpp della sequenza:

void sequenza::inserisci_dopo(const value_type &input){

if(testa==NULL){
inserisci_in_testa(testa, input);
cursore=testa;
precursore=testa;
num_nodi++;
//cout<<"questo è il cursore: "<<cursore->valore()<<endl;

}
else{
precursore=cursore;
cursore=new nodo(input,cursore);
num_nodi++;
}

}

void sequenza::rimuovi_corrente(){

}


void sequenza::stampa_sequenza(){

for(inizia(); cursore!=coda; avanza()){
cout<<cursore->valore();
cout<<endl;
}
}
 
Inizio a farti delle mie considerazioni:
  • Il punto e virgola per separare i metodi (funzioni membro), non serve. Se implementi i metodi direttamente nella classe (inline) bastano le parentesi graffe, altrimenti separi dichiarazione (nel file .h) e implementazione (nel file .cpp) e a quel punto metti il punto e virgola, ma non metti le graffe.
  • Le funzioni lunghezza, inserisci_in_testa, inserisci, rimuovi_in_testa e rimuovi, non hanno senso. Se lavorano su un'istanza di nodo, la OOP vuole che siano metodi (funzioni membro).
  • Quello che hai chiamato nodo è in realtà una lista (linked list), quello che hai chiamato sequenza è in realtà una lista doppiamente linkata (doubly linked list). Ovvero è esattamente come nodo, solo che hai la possibilità di scorrere la lista in due direzioni (avanti e indietro) invece che in una sola (in nodo hai solo next, quindi solo avanti). Quello che ti è sfuggito, è che nell'implementazione di sequenza non avresti dovuto usare node (ciò non toglie che le due classi sono molto simili, quindi puoi prendere spunto).
Se condividi quello che ho scritto, puoi provare a implementare Sequenza senza usare Nodo (nota: per convenzione i nomi delle classi iniziano per una lettera maiuscola). Altrimenti controllo il tuo codice e vediamo di risolverti il problema, ma secondo me non è il caso di farlo perché l'approccio è sbagliato fin dal principio.
 
Innanzitutto grazie per aver risposto.
Sto usando questo approccio poichè il libro di testo consigliato dal mio prof utilizza esattamente questi metodi (la lista la chiama nodo, la sequenza la fa in quel modo...).
Condivido ciò che hai detto perchè cercando un pò sul web, la lista viene fatta con una classe lista unita ad una struct nodo, che mi pare abbia più senso, tuttavia il mio libro di testo (forse l'unico) non utilizza questo approccio.
Il libro di testo è il main and savitch, "Data Stuctures & Other Objects using C++".
Comunque St3ve, mi stai consigliando di implementare Sequenza trattandola come una lista doppiamente puntata, ho capito bene?
 
Condivido ciò che hai detto perchè cercando un pò sul web, la lista viene fatta con una classe lista unita ad una struct nodo, che mi pare abbia più senso, tuttavia il mio libro di testo (forse l'unico) non utilizza questo approccio.
Questo era quello che avevo detto nel mio secondo punto: sostanzialmente stai mixxando il modo alla C (usare funzioni) con il modo alla C++ (usare la classi). Per quanto non sia per niente elegante, non è qui il problema principale. Il punto più importante era il terzo.

Comunque St3ve, mi stai consigliando di implementare Sequenza trattandola come una lista doppiamente puntata, ho capito bene?
Più che un consiglio, è la mia interpretazione dell'esercizio: "Le variabili private sono: un cursore, che mantiene l'elemento attuale, un precursore, che mantiene l'elemento prima di quello attuale, una testa ed una coda". Se tralasciamo "una testa ed una coda", questa è una normalissima doubly-linked list (lista doppiamente puntata), che la si implementa aggiungendo un puntatore *prev alla classe nodo. Se consideriamo anche "una testa ed una coda", il modo più sensato per implementarla è aggiungendo una nuova classe Sequenza che conterrà la lista (rappresentata dalla nostra classe nodo modificata per essere doubly-linked), la testa e la coda (che saranno delle reference ai rispettivi pezzi della lista).

Questo è come ho interpretato quello che hai scritto, ma magari non hai copiato per filo e per segno il testo dell'esercizio e dunque la mia è una considerazione distorta, basata sul modo in cui tu hai interpretato l'esercizio.
 
Ho ricontrollato per sicurezza e il libro mi detta la traccia che ho scritto nel post.
Comunque ho capito come devo procedere, però preferisco ripartire dalla costruzione della lista tramite un nodo.
Grazie mille ^_^
 
Stato
Discussione chiusa ad ulteriori risposte.