Guida [Source] Gestione Stack

ManHunter

Utente Jade
14 Settembre 2009
985
111
780
818
Ultima modifica da un moderatore:
Salve a tutti,

oggi cercherò di spiegarvi come realizzare una struttura dati che si comporti come uno stack. Uno stack è una struttura dati che assume un comportamento particolare durante l'estrazione dei dati. Tale comportamento è detto L.I.F.O., acronimo di Last In First Out. In parole povere, in questa struttura l'ultimo elemento inserito sarà il primo ad essere estratto.
Per operare su questa struttura, utilizzeremo due funzioni principali: push() e pop(). La funzione di push si occuperà di inserire dati all'interno dello stack mentre la funzione pop si occuperà di estrarre dati da esso. Utilizzeremo, inoltre, altre funzioni di appoggio.
Iniziamo!

Per prima cosa, creiamo la nostra struttura:
C:
typedef int tInfo; /*dichiariamo un tipo di dato equivalente ad un intero. Potete cambiare da intero a qualsiasi tipo vogliate, anche una struttura.*/

struct tagStack{
    tInfo *stack;
    int stkPtr;
    int capacity;
    }; /*dichiariamo una struttura dati formata da un puntatore ad un tInfo, un un indice di stack e da un intero che indica la capacità massima*/
typedef struct tagStack tStack; /*definiamo un tipo di dato equivalente alla struttura appena dichiarata*/


Implementiamo ora le funzioni che operano sul nostro stack.
Abbiamo bisogno di:
- creazione dello stack
- distruzione dello stack
- inserimento di dati
- estrazione di dati
- funzioni di appoggio

Creazione stack - tStack* stackCreate( int );
C:
tStack* stackCreate( int ){
    tStack* tmp;

    tmp->stack = ( tInfo * ) malloc( size * sizeof( tInfo ) );
    tmp->capacity = size;
    tmp->stkPtr = 0;

    return tmp;
}

Distruzione stack - tStack* stackDelete( tStack * );
C:
tStack* stackDelete( tStack *stack ){
    stack->capacity = 0;
    stack->stkPtr = 0;
    free(stack);

    return stack;
}

Inserimento dati - void push( tStack*, tInfo );
C:
void push( tStack *stack, tInfo info ){
    stack->stack[stack->stkPtr] = info;
    stack->stkPtr++;
}

Estrazione dati - tInfo pop( tStack* );
C:
tInfo pop( tStack *stack ){
    stack->stkPtr--;
    return stack->stack[stack->stkPtr];
}

Funzione predicativa - bool isEmpty( tStack* );
C:
bool isEmpty( tStack *stack ){
    if( stack->stkPtr <= 0 )
        return true;
    return false;
}

Funzione predicativa - bool isFull( tStack* );
C:
bool isFull( tStack *stack ){
    if( stack->stkPtr == stack->capacity )
        return true;
    return false;
}

Queste dovrebbero essere le funzioni necessarie: nulla toglie che potete implementarne di altre...
Inserisco anche il progetto completo, compreso di main() per testare il funzionamento delle funzioni.

- stack.h -
C:
#ifndef STACK_H
#define STACK_H

#include <stdlib.h>
#include <stdbool.h>

typedef int tInfo;

struct tagStack{
    tInfo *stack;
    int stkPtr;
    int capacity;
    };
typedef struct tagStack tStack;

tStack* stackCreate( int );
tStack* stackDelete( tStack * );

tInfo pop( tStack * );
void push( tStack *, tInfo );

bool isEmpty( tStack * );
bool isFull( tStack * );

#endif

- stack.c -
C:
#include "stack.h"

tStack* stackCreate( int size ){
    tStack* tmp;

    tmp->stack = ( tInfo * ) malloc( size * sizeof( tInfo ) );
    tmp->capacity = size;
    tmp->stkPtr = 0;

    return tmp;
}

tStack* stackDelete( tStack *stack ){
    stack->capacity = 0;
    stack->stkPtr = 0;
    free(stack);
    return stack;
}

tInfo pop( tStack *stack ){
    stack->stkPtr--;
    return stack->stack[stack->stkPtr];
}

void push( tStack *stack, tInfo info ){
    stack->stack[stack->stkPtr] = info;
    stack->stkPtr++;
}

bool isEmpty( tStack *stack ){
    if( stack->stkPtr <= 0 )
        return true;
    return false;
}

bool isFull( tStack *stack ){
    if( stack->stkPtr == stack->capacity )
        return true;
    return false;
}

- main.c -
C:
#include <stdio.h>
#include "stack.h"

int main(){
    tStack *stack;
    int scelta, size;
    tInfo info;

    printf( "\t\tGestione di uno stack\n____________________________________________________\n\n" );
    printf( "Dimensione stack\t>" );
    scanf( "%d", &size );

    stack = stackCreate( size );

    do{
        system( "CLSC" );
        printf( "Scegli cosa fare:\n\n" );
        printf( "1) Inserire elemento\n" );
        printf( "2) Prelevare elemento\n" );
        printf( "3) isEmpty\n" );
        printf( "4) isFull\n" );
        printf( "5) Dealloca lista\n" );
        printf( "6) Esci\n\n" );
        printf( "__________________________________________\n\n" );
        scanf( "%d", &scelta );

        switch( scelta ){
            case 1:
                printf( "Informazione da inserire\t>" );
                scanf( "%d", &info );
                push( stack, info );
                printf( "\n" );
                break;
            case 2:
                printf( "L'elemento prelevato \212:\t%d\n", pop( stack ) );
                break;
            case 3:
                if( isEmpty( stack ) )
                    printf( "Lo stack \212 vuoto.\n" );
                else
                    printf( "Lo stack non \212 vuoto.\n" );
                break;
            case 4:
                if( isFull( stack ) )
                    printf( "Lo stack \212 pieno.\n" );
                else
                    printf( "Lo stack non \212 pieno.\n" );
                break;
            case 5:
                stack = stackDelete( stack );
                if( stack == NULL )
                    printf( "Stack deallocato\n" );
                else
                    printf( "Stack non deallocato\n" );
                break;
            case 6:
                printf( "Hai scelto di uscire!" );
                return EXIT_SUCCESS;
        }
        system( "PAUSE" );
    }while( scelta != 6 );

    return EXIT_SUCCESS;
}

E questo è tutto. Per eventuali malfunzionamenti o consigli potete contattarmi in privato oppure scrivere qui di seguito.

Logo1.png


Saluti.
 
  • Mi piace
Reazioni: Sn0w
Non è così difficile come sembra, anzi... E' una struttura dati che viene gestita e funziona (logicamente) come lo stack del processore...
 
Ad esempio quello di usarlo creando poi un contesto per una macchina virtuale. Tecnica ad oggi parecchio utilizzata nei sistemi di protezione di applicazioni per windows.
 
Ultima modifica da un moderatore:
stack e coda (queue) sono due strutture dati fondamentali nell'imnplementazione di algoritmi ricorsivi senza usare la ricorsione (forte, no?), nella navigazione di alberi e grafi, versione piu' complicata della struttura dati lista.

Sia implementativamente che concettualmente sono estremamente semplici:

hanno due lati: una testa (head) ed una coda (tail) (immaginatevi un verme)

per lo stack inserite gli elementi dal lato della testa, e li estraete dal lato della testa
per la coda (queue) inserite gli elementi dal lato della coda (tail), e li estraete dal lato della testa

Ad esempio: consideriamo lo stack e supponiamo di inserire i numeri 1,2,3

[] stack vuoto
[1]
[1,2]
[1,2,3]

ora estraggo gli elementi:

[1,2], 3
[1], 2
[], 1

quindi, inserisco 1,2,3, ed estraggo 3,2,1


Ora consideriamo la coda:

[]: coda vuota
[1]
[2,1]
[3,2,1]

ora estraggo gli elementi

[3,2], 1
[3], 2
[], 3

quindi, inserisco 1,2,3, ed estraggo 1,2,3


Lo stack e' una struttura LIFO: Last In, First Out, Ultimo Inserito, Primo ad Uscire
La coda e' una struttura FIFO: First In First Out: Primo Inserito, Primo ad Uscire

Chissa' perche' non si dice LILO: Last In, Last Out, Ultimo Inserito, Ultimo ad Uscire, boh!

Le implementazioni possibili, per stack e coda, sono essenzialmente 2:

mediante una lista linkata,
o come un vettore, come indicato nel primo post.

Poiche' il vettore ha una dimensione massima, o si prevede di non inserire piu' di tot elementi nello stack/coda, oppure bisogna prevedere un sistema di ridimensionamento del vettore.

La lista non ha il problema della dimensione massima, ma e' leggermente meno efficiente perche' bisogna giocare con i puntatori, e allocare e deallocare delle piccole quantita' di memoria ogni volta che si inserisce o si estrae un elemento.
 
  • Mi piace
Reazioni: AlexJ
ciao, tutto molto chiaro, però essendo ancora un principiante non conosco ancora bene la sintassi del c, potresti spiegarmi queste due righe di codice cosa fanno?
stack->stack[stack->stkPtr] = info;
return stack->stack[stack->stkPtr];
in particolare il comando "stack[stack->stkPtr]"
sono nella funzione push e pop rispettivamente, grazie ;)