Problema alberi Rosso-Neri in C

di il
3 risposte

Problema alberi Rosso-Neri in C

Salve a tutti, sto cercando di fare un programma in C che legge riga per riga da un file .txt, salva i dati direttamente nei vari nodi, salvandoli all'inizio in ordine di tempo e poi tramite menù a schermo dovrebbe essere possibile all'utente decidere quale valore cercare all'interno dell'albero. In questa parte faccio una copia dell'albero di partenza riorganizzando l'ordine dell'albero a seconda del tipo indicato (tempo, gas o elettricità), cancello il vecchio albero e salvo la vecchia sentinella dandole l'indirizzo del nuovo albero copiato.
Il problema è che a tempo di copmilazione dà segmentation fault quando prova a fare il ripristino dell'equilibrio e non riesco a capirne il motivo. So che il segmentation fault è dato quando viene seguito un puntatore nullo ma non riesco a capire quale puntatore è nullo né perchè, neanche usando il debugger. Qualcuno riesce a capire che cosa sto sbagliando? Allego il codice qui sotto:

/*DIRETTIVE AL PREPROCESSORE*/
#include<stdio.h>
#include<stdlib.h>          //serve per malloc
#define bool int
#define true 1
#define false 0

/*DEFINIZIONE DEI TIPI*/
typedef enum {rosso, nero} colore_t;

//definizione del tipo di struttura nodo
typedef struct nodo_albero_bin_rn
{
    int                             tempo;
    double                          gas,
                                    elettricita;
    colore_t                        colore;
    struct  nodo_albero_bin_rn      *sx,        //collegamento a nodo sinistro
                                    *dx,        //collegamento a nodo destro
                                    *padre;     //collegamento al nodo padre
} nodo_albero_bin_rn_t;


/*DICHIARAZIONE DELLE FUNZIONI*/
int scelta_operazione(void);
void pulisci_buffer(void);
int inserisci_in_albero_bin_ric_rn(nodo_albero_bin_rn_t *sent_p, int tem, double g, double elet);
void ripristina_ins_albero_bin_ric_rn(nodo_albero_bin_rn_t *sent_p, nodo_albero_bin_rn_t *nodo_p);
void ruota_sx(nodo_albero_bin_rn_t *sent_p, nodo_albero_bin_rn_t *x_p);
void ruota_dx(nodo_albero_bin_rn_t *sent_p, nodo_albero_bin_rn_t *x_p);
void visita_albero_bin_simm(nodo_albero_bin_rn_t *nodo_p, nodo_albero_bin_rn_t *sent_p);
void cerca_valore(nodo_albero_bin_rn_t *sent_p, double valore, int *tipo_p);
void copia_albero_bin_post(nodo_albero_bin_rn_t *nodo_p, nodo_albero_bin_rn_t *sent_vecchia, nodo_albero_bin_rn_t *sent_nuova, int *tipo_p);
int inserisci_nuovo(nodo_albero_bin_rn_t *sent_vecchia, nodo_albero_bin_rn_t *sent_nuova, int *tipo_p);
void cancella_albero(nodo_albero_bin_rn_t *sent_p, nodo_albero_bin_rn_t *sent_nuova);
void cancella_nodi_post(nodo_albero_bin_rn_t *nodo_p, nodo_albero_bin_rn_t *sent_p);

/*DEFINIZIONE DELLE FUNZIONI*/
// Funzione main
int main(int argc, const char * argv[]) {

    int                 tipo = 1,                       //input: tipo di valore da cercare
                        *tipo_p = &tipo,                //input: puntatore a tipo
                        scelta,                         //lavoro: operazione scelta
                        ins,                            //lavoro: operazione andata a buon fine di inserimento nodo
                        tem;                            //lavoro: proprieta' tempo del nodo
    double              valore,                         //input: valore da cercare
                        g,                              //lavoro: proprieta' gas del nodo
                        elet;                           //lavoro: proprieta' elettricità del nodo

    //lavoro: radice albero principale
    nodo_albero_bin_rn_t *sent_p = NULL;
    sent_p = (nodo_albero_bin_rn_t *)malloc(sizeof(nodo_albero_bin_rn_t));
    sent_p->sx = sent_p->dx = sent_p;
    sent_p->colore = nero;
    sent_p->padre = NULL;

    //lavoro: radice albero copia
    nodo_albero_bin_rn_t *sent_nuova = NULL;
    sent_nuova = (nodo_albero_bin_rn_t *)malloc(sizeof(nodo_albero_bin_rn_t));
    sent_nuova->sx = sent_nuova->dx = sent_nuova;
    sent_nuova->colore = nero;
    sent_nuova->padre = NULL;

    //apertura file per acquisizione dati
    FILE *file_dati = fopen("dati_riscaldamento.txt","r");
    if (file_dati==NULL)
    {
        printf("Questo file non esiste.\n");
    }
    else
    {
        //dichiaro che i parametri del nuovo nodo creato devono avere valori uguali a quelli letti dal file
        while (fscanf(file_dati, "%d %lf %lf",
                        &tem, &g, &elet)
                        != EOF)
        {

            //funzione di inserimento dei nodi
            ins = inserisci_in_albero_bin_ric_rn(sent_p, tem, g, elet);
            /* if (ins==0)
                printf("Duplicate found!\n"); */

        }//end of while
    }//end fopen
    //chiusura file acquisizione dati
    fclose(file_dati);

    printf("Tempo\t\tGas\t\t\tElettricita'\n");
    visita_albero_bin_simm(sent_p->sx,sent_p);
    printf("Dati caricati correttamente dal file\n");

    do
    {
        /* Stampiamo il menu delle scelte */
        scelta = scelta_operazione();

        switch (scelta)
        {
        case 1:
            /* Cerca i dati relativi a una determianta rilevazione */
            printf("Scegli il parametro da cercare:\n 1.Tempo 2.Gas 3.Elettricita'\n");
            scanf("%d", &tipo);
            printf("Inserisci il valore da cercare\n"
                   "(es. di formati di ricerca: tempo - aaaammgghh, gas - 0.0, elettricita' - 0.0):\n");
            scanf("%lf", &valore);
            copia_albero_bin_post(sent_p->sx, sent_p, sent_nuova, &tipo);
            cancella_albero(sent_p, sent_nuova);
            cerca_valore(sent_p, valore, &tipo);

            break;
        /*
        case 2:
            //da fare
            Cancella i dati corrispondenti a una determinata rilevazione
            printf("Scegli il parametro da cancellare:\n 1.Tempo 2.Gas 3.Elettricita'\n");
            scanf("%d", &tipo);
            printf("Inserisci il valore da cercare:\n");
            scanf("%lf", &valore);
            cerca_valore(sent_p, valore, &tipo);
            //funzione di rimozione
            break;
        default:
            return 0;
            break; */
        }
    } while (scelta != 2);

    return 0;
}//end main

// Altre funzioni
// Funzione che stampa il menu
int scelta_operazione(void)
{
    /* Definizione delle variabili locali relative alla funzione */
    bool esito_operazione = true; /* lavoro: esisto operazioni funzione */
    int scelta,                   /* input: operazione da eseguire */
        esito_lettura;            /* lavoro: esito lettura scanf */

    do
    {
        esito_operazione = true;

        printf("\nScegliere se si vuole:\n");
        printf("[1] Cercare e stampare i dati relativi a una determinata rilevazione\n");
        printf("[2] Cancellare i dati relativi a una determinata rilevazione\n");
        printf("[3] Uscire\n");
        esito_lettura = scanf("%d", &scelta);

        /* Svuotiamo il buffer da eventuali caratteri in eccesso */
        pulisci_buffer();

        if (esito_lettura != 1 || scelta < 1 || scelta > 3)
        {
            printf("Errore: inserire un numero da 1 a 3.\n");
            esito_operazione = false;
        }
    } while (!esito_operazione);

    return scelta;
}//end scelta_operazione

// Funzione che pulisce il buffer di stdin
void pulisci_buffer(void)
{
    /* Definizione delle variabili locali relative alla funzione */
    char carattere_rimosso; /* lavoro: variabile pulitura buffer input */

    do
    {
        carattere_rimosso = getchar();
    } while (carattere_rimosso != '\n');
}

int inserisci_in_albero_bin_ric_rn(nodo_albero_bin_rn_t *sent_p, int tempo, double gas, double elettricita) {
    int inserito;
    nodo_albero_bin_rn_t *nodo_p, *padre, *nuovo_p;

    for(nodo_p = sent_p->sx, padre = sent_p;
        ((nodo_p != sent_p) && (nodo_p->tempo != tempo));
        padre = nodo_p, nodo_p = (tempo < nodo_p->tempo)? nodo_p->sx:nodo_p->dx)
        ;

    if(nodo_p != sent_p)
        inserito = 0;
    else {
        inserito = 1;
        nuovo_p = (nodo_albero_bin_rn_t *)malloc(sizeof(nodo_albero_bin_rn_t));
        nuovo_p->tempo = tempo;
        nuovo_p->gas = gas;
        nuovo_p->elettricita = elettricita;
        nuovo_p->colore = rosso;
        nuovo_p->sx = nuovo_p->dx = sent_p;
        nuovo_p->padre = padre;

        if(padre == sent_p) {
            sent_p->sx = sent_p->dx = nuovo_p;
        } else {
            if(tempo < padre->tempo)
                padre->sx = nuovo_p;
            else
                padre->dx = nuovo_p;
        }
        ripristina_ins_albero_bin_ric_rn(sent_p, nuovo_p);
    }
    return(inserito);
}

void ripristina_ins_albero_bin_ric_rn(nodo_albero_bin_rn_t *sent_p,
                                      nodo_albero_bin_rn_t *nodo_p) {
    nodo_albero_bin_rn_t *zio_p;

    while(nodo_p->padre->colore == rosso) {
        if (nodo_p->padre == nodo_p->padre->padre->sx) {
            zio_p = nodo_p->padre->padre->dx;
            if (zio_p->colore == rosso) {
                nodo_p->padre->colore = nero;
                zio_p->colore = nero;
                nodo_p->padre->padre->colore = rosso;
                nodo_p = nodo_p->padre->padre;
            }
            else {
                if (nodo_p == nodo_p->padre->dx) {
                    nodo_p = nodo_p->padre;
                    ruota_sx(sent_p, nodo_p);
                }
            }
            nodo_p->padre->colore = nero;
            nodo_p->padre->padre->colore = rosso;
            ruota_dx(sent_p, nodo_p->padre->padre);
        }
        else {
            zio_p = nodo_p->padre->padre->sx;
            if (zio_p->colore == rosso) {
                nodo_p->padre->colore = nero;
                zio_p->colore = nero;
                nodo_p->padre->padre->colore = rosso;
                nodo_p = nodo_p->padre->padre;
            }
            else {
                if (nodo_p == nodo_p->padre->sx) {
                    nodo_p = nodo_p->padre;
                    ruota_dx(sent_p, nodo_p);
                }
            }
            nodo_p->padre->colore = nero;
            nodo_p->padre->padre->colore = rosso;
            ruota_sx(sent_p, nodo_p->padre->padre);
        }
    }
    sent_p->sx->colore = nero;
}//end ripristina_ins_albero_bin_ric_rn

void ruota_sx(nodo_albero_bin_rn_t *sent_p, nodo_albero_bin_rn_t *x_p) {
    nodo_albero_bin_rn_t *y_p;

    y_p = x_p->dx;
    x_p->dx = y_p->sx;
    if (y_p->sx != sent_p)
        y_p->sx->padre = x_p;
    y_p->padre = x_p->padre;
    if(x_p == sent_p->sx) {
        sent_p->sx = sent_p->dx = y_p;
    }
    else {
        if(x_p == x_p->padre->sx) {
            x_p->padre->sx =y_p;
        }
        else {
            x_p->padre->dx = y_p;
        }
    }
    y_p->sx = x_p;
    x_p->padre = y_p;
}//end ruota_sx

void ruota_dx(nodo_albero_bin_rn_t *sent_p, nodo_albero_bin_rn_t *x_p) {
    nodo_albero_bin_rn_t *y_p;

    y_p = x_p->sx;
    x_p->sx = y_p->dx;
    if (y_p->dx != sent_p)
        y_p->dx->padre = x_p;
    y_p->padre = x_p->padre;
    if(x_p == sent_p->dx) {
        sent_p->dx = sent_p->sx = y_p;
    }
    else {
        if(x_p == x_p->padre->dx) {
            x_p->padre->dx =y_p;
        }
        else {
            x_p->padre->sx = y_p;
        }
    }
    y_p->dx = x_p;
    x_p->padre = y_p;
}//end ruota_dx

void visita_albero_bin_simm(nodo_albero_bin_rn_t *nodo_p, nodo_albero_bin_rn_t *sent_p) {
    if (nodo_p != sent_p) {
        visita_albero_bin_simm(nodo_p->sx, sent_p);
        printf("%d\t\t\t%.2f\t\t\t\t%.2f\n",
                nodo_p->tempo,
                nodo_p->gas,
                nodo_p->elettricita);
        visita_albero_bin_simm(nodo_p->dx, sent_p);
    }
}//end visita_albero_bin_simm



// cerca un valore
void cerca_valore(nodo_albero_bin_rn_t *sent_p, double valore, int *tipo_p)
{
    nodo_albero_bin_rn_t *nodo_p;

    if(*tipo_p == 1)
        {
            valore = (int) valore;
            for (nodo_p = sent_p->sx;
            nodo_p != sent_p && nodo_p->tempo != valore;
            nodo_p = (valore < nodo_p->tempo)? nodo_p->sx : nodo_p->dx)
            ;
        }
        else if(*tipo_p == 2)
        {
            for (nodo_p = sent_p->sx;
            nodo_p != sent_p && nodo_p->gas != valore;
            nodo_p = (valore < nodo_p->gas)? nodo_p->sx : nodo_p->dx)
            ;
        }
        else if(*tipo_p == 3)
        {
           for (nodo_p = sent_p->sx;
            nodo_p != sent_p && nodo_p->elettricita != valore;
            nodo_p = (valore < nodo_p->elettricita)? nodo_p->sx : nodo_p->dx)
            ;
        }
        else {
            printf("Numero inserito sbagliato, si prega di riprovare.\n");
            return;
        }

    {
        if(nodo_p == sent_p)       //se non trova l'elemento cercato fino alla fine
                {
                    printf("L'elemento cercato non è presente nella rilevazione.\n");
                    return;                                                         //esce dalla funzione
                }
        else
        {
        printf("Tempo\t\t\t\tGas\t\t\t\tElettricita'\n");
        printf("%d\t\t%.2f\t\t%.2f\n",
                nodo_p->tempo,
                nodo_p->gas,
                nodo_p->elettricita);
        }

    }
}//end cerca_valore


//chiamato in originale con sent_p->sx e sent_p
void copia_albero_bin_post(nodo_albero_bin_rn_t *nodo_p, nodo_albero_bin_rn_t *sent_vecchia, nodo_albero_bin_rn_t *sent_nuova, int *tipo_p)
{
    if (nodo_p != sent_vecchia) {
        copia_albero_bin_post(nodo_p->sx, sent_vecchia, sent_nuova, tipo_p);
        copia_albero_bin_post(nodo_p->dx, sent_vecchia, sent_nuova, tipo_p);
        inserisci_nuovo(nodo_p, sent_nuova, tipo_p);

    }
}//end copia_albero_bin_post

int inserisci_nuovo(nodo_albero_bin_rn_t *sent_vecchia, nodo_albero_bin_rn_t *sent_nuova, int *tipo_p)
{
    int inserito;
    nodo_albero_bin_rn_t *nodo_p = NULL, *padre, *nuovo_p;

    if(*tipo_p == 1)
    {
        for(nodo_p = sent_nuova->sx, padre = sent_nuova;
        ((nodo_p != sent_nuova) && (nodo_p->tempo != sent_nuova->tempo));
        padre = nodo_p, nodo_p = (sent_nuova->tempo < nodo_p->tempo)? nodo_p->sx:nodo_p->dx)
        ;
    }
    else if(*tipo_p == 2)
    {
        for(nodo_p = sent_nuova->sx, padre = sent_nuova;
        ((nodo_p != sent_nuova) && (nodo_p->gas != sent_nuova->gas));
        padre = nodo_p, nodo_p = (sent_nuova->gas < nodo_p->gas)? nodo_p->sx:nodo_p->dx)
        ;
    }
    else if(*tipo_p == 3)
    {
        for(nodo_p = sent_nuova->sx, padre = sent_nuova;
        ((nodo_p != sent_nuova) && (nodo_p->elettricita != sent_nuova->elettricita));
        padre = nodo_p, nodo_p = (sent_nuova->elettricita < nodo_p->elettricita)? nodo_p->sx:nodo_p->dx)
        ;
    }

    if(nodo_p != sent_nuova)
        inserito = 0;
    else {
        inserito = 1;
        nuovo_p = (nodo_albero_bin_rn_t *)malloc(sizeof(nodo_albero_bin_rn_t));
        nuovo_p->tempo = sent_vecchia->tempo;
        nuovo_p->gas = sent_vecchia->gas;
        nuovo_p->elettricita = sent_vecchia->elettricita;
        nuovo_p->colore = rosso;
        nuovo_p->sx = nuovo_p->dx = sent_nuova;
        nuovo_p->padre = padre;

        if(padre == sent_nuova) {
            sent_nuova->sx = sent_nuova->dx = nuovo_p;
        } else {
                if(*tipo_p == 1)
                {
                    if(nuovo_p->tempo < padre->tempo)
                        padre->sx = nuovo_p;
                    else
                        padre->dx = nuovo_p;
                }
                else if(*tipo_p == 2)
                {
                    if(nuovo_p->gas < padre->gas)
                        padre->sx = nuovo_p;
                    else
                        padre->dx = nuovo_p;
                }
                else if(*tipo_p == 3)
                {
                    if(nuovo_p->elettricita < padre->elettricita)
                        padre->sx = nuovo_p;
                    else
                        padre->dx = nuovo_p;
                }
        }
        ripristina_ins_albero_bin_ric_rn(sent_nuova, nuovo_p);
    }
    return(inserito);
}//end inserisci_nuovo


void cancella_albero(nodo_albero_bin_rn_t *sent_p, nodo_albero_bin_rn_t *sent_nuova)
{
    cancella_nodi_post(sent_p->sx, sent_p);
    sent_p = sent_nuova;
    visita_albero_bin_simm(sent_p->sx,sent_p);
    free(sent_nuova);
}


void cancella_nodi_post(nodo_albero_bin_rn_t *nodo_p, nodo_albero_bin_rn_t *sent_p)
{
    if (nodo_p != sent_p) {
        cancella_nodi_post(nodo_p->sx, sent_p);
        cancella_nodi_post(nodo_p->dx, sent_p);
        free(nodo_p);
    }
}//end cancella_nodi_post
Il file .txt contiene queste righe (int double double):

2019042908 1.3 2.70
2019042909 0.3 4.26
2019042910 8.3 5.14
2019042911 9.2 7.00
2019042912 7.1 4.56
2019042913 6.0 5.78
2019042914 5.6 3.02

3 Risposte

  • Re: Problema alberi Rosso-Neri in C

    L'errore si manifesta nella funzione

    ripristina_ins_albero_bin_ric_rn

    nella riga

    nodo_p->padre->padre->colore = rosso;

    perché

    nodo_p->padre->padre

    è NULL.

    Devi capire tu il perché.
  • Re: Problema alberi Rosso-Neri in C

    Sì, col debugger avevo capito che il problema è lì, è che non riesco a capirne il motivo. Puoi per favore darmi qualche suggerimento in più? Perchè così rimango al punto di partenza
  • Re: Problema alberi Rosso-Neri in C

    Veramente avevi scritto
    ma non riesco a capire quale puntatore è nullo
    e io ti ho detto quale e in quale funzione quindi non avevi capito che il problema era lì.

    Adesso perché sia NULL dipende dall'algoritmo che hai implementato e sinceramente ci vorrebbe un po' di tempo per controllarlo, potrebbe essere tutto sbagliato ...

    Sono convinto che visto il problema e la posizione, tu che hai seguito una certa logica nella scrittura del codice, dovresti essere più veloce nel trovare l'inghippo. Perché l'hai scritto tu tutto il codice, vero?
Devi accedere o registrarti per scrivere nel forum
3 risposte