Non capisco come impostare questo esercizio sulla struttura dati Pila

di il
6 risposte

Non capisco come impostare questo esercizio sulla struttura dati Pila

Salve ragazzi ho ancora necessità di alcuni vostri consigli che per molti di voi saranno stupidi.
Abbiate pietà di me ma sto passando un brutto periodo e la mia conoscenza della programmazione ad oggetti (anche grazie ad un prof inutile) è davvero precaria.
Non riesco a capire come impostare questo esercizio.

Ho la seguente implementazione della struttura dati Pila fatta da me:


#include <iostream>
#include <assert.h>
using namespace std;

template <class T>
class Pila {

	public:

		//Costruttori e Distruttore
		Pila();
		Pila(int n);
		~Pila();

		//Metodi delle specifiche
		void creaPila();
		bool pilaVuota() const;
		T leggiPila() const;
		void fuoriPila();
		void inPila(T nuovo);

	private:
		T *elementi;
		int MAX;
		int testa;

};


template <class T>
Pila<T>::Pila(){

	elementi = new T[100];
	MAX = 100;
	creaPila();
}

template <class T>
Pila<T>::Pila(int n){

	elementi = new T[n];
	MAX = n;
	creaPila();
}

template <class T>
Pila<T>::~Pila(){

	delete[] elementi;
}

template <class T>
void Pila<T>::creaPila(){

	testa = 0;
}

template <class T>
bool Pila<T>::pilaVuota() const {

	return testa == 0;
}

template <class T>
T Pila<T>::leggiPila() const {

	assert(testa > 0);
	return elementi[testa - 1];

}

template <class T>
void Pila<T>::fuoriPila(){

	if(!pilaVuota())
		testa--;
	else
		cout << "Nessun elemento nella lista" << endl;
}

template <class T>
void Pila<T>::inPila(T nuovo){

	if(testa == MAX)
		cout << "Raggiunta capienza massima" << endl;
	else
	{
		elementi[testa] = nuovo;
		testa++;
	}
}

Fin qui tutto bene, utilizzando questa struttura dati dovrei svolgere il seguente esercizio:

TRACCIA ESERCIZIO:
Progettare ed implementare un classe MultipleStack che fornisca la gestione di m stack. La dichiarazione della classe dovrebbe essere simile a qualcosa del genere:
class MultipleStack
{
// ...
public:
MultipleStack (unsigned int);
void Push (Object&, unsigned int);
Object& Pop (unsigned int);
// ...
};
- Il costruttore ha in input un argomento di tipo intero che specifica il numero di stack da gestire
- la funzione Push ha due argomenti. Il primo è l'oggetto da inserire e il secondo specifica lo stack in cui inserirlo
- la funzione Pop ha in input un solo intero che specifica lo stack da cui eliminare un oggetto

Scegliere una delle seguenti implementazioni:
- tenere tutti gli stack in un solo array
- usare un array di oggetti di tipo Stack
- usare una lista collegata di oggetti di tipo Stack

FINE TRACCIA

Quello che mi chiedo è:
1. Questa classe deve essere un espansione della mia classe Pila? o deve essere una classe totalmente nuova che usa la struttura dati Pila grazie ad un #include "Pila.h" ???
2. il prof nella traccia ha definito il tipo "Object" senza mai averne accennato, ora mi chiedo: si tratta di un oggetto generico esattamente come funziona per Java? Se si, in quale libreria si trova dato che il compilatore non riconosce il tipo?
Se invece "Object" è solo un modo per farmi capire che devo usare la mia struttura dati mi chiedo: come faccio a passare una classe template per riferimento in una classe totalemente nuova??

Spero di aver esposto bene i miei dubbi, mi rendo conto che potrebbero essere un pò confusi (ma del resto io sono confuso!), potete darmi delle dritte (anche senza scrivere codice) sul come impostare questo esercizio?

6 Risposte

  • Re: Non capisco come impostare questo esercizio sulla struttura dati Pila

    1) ci sono tante soluzioni quante le teste dei programmatori !!
    2) e' ovvio che con l'esperienza certe scelte diventeranno ovvie/obbligatorie

    Questo per dire: PROVA!
    OGNI soluzione che funziona, va bene.

    PRIMA della programmazione ad oggetti, DEVI avere CHIARO COME dovrebbe funzionare.

    POI fai l'implementazione.

    Un modo per avere chiaro il funzionamento e' ragionare con carta e matita e fare dei ""casi d'uso"", cioe' IMMAGINARE vari tipi di operazioni e vedere, partendo da uno stato iniziale, quale dovrebe essere lo stato finale.

    Puoi farlo immaginando di avere PILE di PIATTI di colori diversi, e devi impilare SOLO piatti con lo stesso colore.
  • Re: Non capisco come impostare questo esercizio sulla struttura dati Pila

    migliorabile ha scritto:


    1) ci sono tante soluzioni quante le teste dei programmatori !!
    2) e' ovvio che con l'esperienza certe scelte diventeranno ovvie/obbligatorie

    Questo per dire: PROVA!
    OGNI soluzione che funziona, va bene.

    PRIMA della programmazione ad oggetti, DEVI avere CHIARO COME dovrebbe funzionare.

    POI fai l'implementazione.

    Un modo per avere chiaro il funzionamento e' ragionare con carta e matita e fare dei ""casi d'uso"", cioe' IMMAGINARE vari tipi di operazioni e vedere, partendo da uno stato iniziale, quale dovrebe essere lo stato finale.

    Puoi farlo immaginando di avere PILE di PIATTI di colori diversi, e devi impilare SOLO piatti con lo stesso colore.

    Innanzi tutto grazie della risposta!

    Cerco di spiegare come ho interpretato la traccia io:

    La classe MultipleStack deve gestire un array di Pile.
    In pratica dovrei poter gestire una situazione del genere:

    Pila 1: [ ][ ][ ][ ][ ][ ][ ][ ]
    Pila 2: [ ][ ][ ][ ]
    Pila 3: [ ][ ][ ][ ][ ]
    ....
    Pila m: [ ][ ][ ][ ]

    Il costruttore MultipleStack(unsigned int n) deve creare spazio per n pile, quindi posso creare un array di n dimensioni di tipo Pila.
    Quindi dopo aver chiamato il costruttore dovrei avere un array di n celle dove ogni cella è una Pila.

    Il metodo Push(Object&, unsigned int p) prende un oggetto e lo inserisce nella pila che si trova nella p-esima posizione dell'array di pile.

    Il metodo Pop(unsigned int) invece elimina invece l'oggetto che si trova in testa nella pila presente nell'array di pile alla posizione ricevuta in input.

    Fin qui ho capito bene??

    Non ho ancora capito però che significa quell'Object, cioè io posso inserire nella pila un oggetto di qualsiasi tipo? Cioè avere una situazione del genere:

    Pila 1: [int ][double][classe X ][classe Y ][altro tipo ][..][.. ][.. ]
    Pila 2: [..][.. ][..][..]
    Pila 3: [..][.. ][..][..][..]
    ....
    Pila m: [..][..][..][..]

    Grazie in anticipo per l'eventuale risposta
  • Re: Non capisco come impostare questo esercizio sulla struttura dati Pila

    È difficile capire cosa voglia il professore, non stiamo nella sua testa. Forse intendeva semplicemente in tipo generico del template.
    Se invece intendeva usare il polimorfismo a runtime, allora devi creare tu una generica classe Object. I puntatori alle liste saranno di tipo Object* e potrai memorizzare nella lista solo oggetti di tipo Object o sue sottoclassi.
  • Re: Non capisco come impostare questo esercizio sulla struttura dati Pila

    Secondo me andare di ereditarietà per implementare la pila multipla non è un buon pattern, perché i due contenitori non condividono né parte dell'interfaccia, né dati membro.
  • Re: Non capisco come impostare questo esercizio sulla struttura dati Pila

    Grazie per le risposte nel frattempo sono arrivato ad una conclusione.
    
    
    #include "Pila.h"
    
    template <class T>
    class MultipleStack {
    
    	public:
    		MultipleStack(unsigned int n);
    		~MultipleStack();
    		void inserisci(T& elemento, unsigned int);
    		void cancella(unsigned int);
    		T leggiTesta(unsigned int);
    
    	private:
    		Pila<T>* array;
    		int dimensione;
    
    
    };
    
    
    template <class T>
    MultipleStack<T>::~MultipleStack(){
    
    	for(int i=0; i<dimensione; i++)
    		array[i].~Pila();
    
    	delete[] array;
    
    }
    
    
    
    template <class T>
    MultipleStack<T>::MultipleStack(unsigned int n){
    
    	array = new Pila<T>[n];
    	dimensione = n;
    
    }
    
    
    
    template <class T>
    void MultipleStack<T>::inserisci(T& elemento, unsigned int p){
    
    	if(p < (unsigned)dimensione)
    		array[p].inPila(elemento);
    	else cout << "Non esiste questa posizione!";
    
    }
    
    
    
    template <class T>
    void MultipleStack<T>::cancella(unsigned int p){
    
    	if(p < (unsigned)dimensione)
    		array[p].fuoriPila();
    	else cout << "Non esiste questa posizione!";
    
    }
    
    
    
    template <class T>
    T MultipleStack<T>::leggiTesta(unsigned int p){
    
    	T elemento;
    	elemento = array[p].leggiPila();
    
    	return elemento;
    
    }
    
    
    Per quanto riguarda il tipo Object il prof ha detto che non dovevo necessariamente creare un MultipleStack di oggetti di ogni tipo, perciò la soluzione che ho adottato sembra andare bene.

    Ora vi chiedo il distruttore sta bene?
    In particolare:
    
    
    template <class T>
    MultipleStack<T>::~MultipleStack(){
    
    	for(int i=0; i<dimensione; i++)
    		array[i].~Pila();
    
    	delete[] array;
    
    }
    
    
    E soppratutto: c'è un modo per testare i distruttori ed essere certi di non creare memory leak?
  • Re: Non capisco come impostare questo esercizio sulla struttura dati Pila

    Avete studiato le liste con i puntatori? Perché è meglio allocare con quelle uno stack, anziché con array.

    Comunque, per quando riguarda i distruttori, starei attento ad azzerare i puntatori dopo aver chiamato i delete, onde evitare che una chiamata doppia del distruttore faccia danni. Inoltre non c'è bisogno di chiamarlo su ogni singolo elemento della pila, viene chiamato in automatico quando viene deallocato l'array della pila:
    
    template <class T>
    MultipleStack<T>::~MultipleStack(){
        if(array != 0)
    	{
    	    delete[] array;
    	    array = 0;
    	}
    	return;
    }
    
    Vale lo stesso per il distruttore della pila.
    Un appunto: dal C++ 11 andrebbe usato nullptr per azzerare i puntatori, non 0.

    Per provare che funzionino, usa una classe di prova:
    
    #include "MultiStack.h"
    
    class Prova
    {
        static int i;
        int n;
        public:
        Prova(){
            n = i;
            i++;}
        ~Prova(){cout<<"Distruzione di "<<n<<endl;}
    };
    int Prova::i=0;
    
    int main()
    {
        MultipleStack<Prova> m(2);
    
        cout<<"Distruggo \n";
        m.~MultipleStack<Prova>();
        cout<<"ciao ciao \n";
        
        return 0;
    
    Output:
    
    Distruggo
    Distruzione di 199
    ...
    Distruzione di 0
    ciao ciao
    
    Ci sono alcune cose che aggiusterei.
    Le funzioni inserisci, sia di Pila che MultiStack è meglio che prendano come argomento sempre dei const reference, onde ad evitare troppe copie inutili.
    es:
    void Pila<T>::inPila(const T& nuovo)
    Vale lo stesso per le funzioni di lettura, in cui volendo puoi farne una versione const e una non const a seconda che tu voglia permettere o meno la modifica dell'elemento. es:
    
    const T& MultipleStack<T>::leggiTesta(unsigned int p) const;
    T& MultipleStack<T>::leggiTesta(unsigned int p);
    
    Ciascuna delle quali chiamerà la rispettiva const e non const della Pila.
Devi accedere o registrarti per scrivere nel forum
6 risposte