/* -------------------------------------------------------------- a l b i n . c Il programma gestisce in maniera completa -inserzione, cancel- lazione, visita- un albero binario non del tipo AVL. E' stato scritto con la tecnica BKF (=Bast Ke Funz). Pertanto potrebbe es- sere migliorabile. Segnatamente la cancellazione. Oltre alle o- perazioni citate, e' prevista la stampa. La cosa piu' sensata sarebbe stata quella di scrivere un applet Java. Poiche' non me la sento di affrontare lo studio di quest'ultimo ma conosco La- TeX, ho sfruttato le sue limitate capacita' grafiche. Sufficien- ti tuttavia, in quanto si tratta di tracciare dei box e delle li- nee. L'operazione di stampa crea un file temporaneo. Da un'altra finestra terminale va lanciato uno script che elabora il contenu- to trasformandolo, tramite un programma C, in statement LaTeX (e' necessaria la presenza di questo pacchetto). Da LaTeX si ot- tiene un file .pdf. Ogni volta che la funzione stampa viene invo- cata, c'e' la sovrascrittura del file temporaneo. La stampa quin- di e' asincrona. Ho messo la massima cura, ma non posso garantire l'assenza di er- rori. Pertanto il tutto va usato cosi' com'e' e a proprio rischio e pericolo. Per la compilazione usare: gcc -ansi -DSTAMPA -O -pedantic -s -W -Wall -o albero albero.c Lo script per la generazione dell'albero grafico e quanto connes- so non sono online. Basta richiederli. -------------------------------------------------------------- */ #include <setjmp.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #define False 0 #define True !False #define albero main #ifdef STAMPA int altbox = 10, altfr = 5, basebox = 10; int curv = 2, trabox = 5; const int box = 5, frdx = 11, frsx = 10; #endif jmp_buf restore; struct foglia { struct foglia *sx; int valore; struct foglia *retro; struct foglia *dx; }; typedef struct foglia* nodo; #ifdef STAMPA void arco (nodo n, char *fn) { char *riga; FILE *f; int a[4], da[4], dim; int isempty (nodo); nodo retro; void vertici (FILE *, int, char *, int); dim = 40; riga = (char *) malloc ((unsigned int) dim); if (isempty (n) == False) { arco (n->sx, fn); if (isempty (n->retro) == False) { f = fopen (fn, "r+"); retro = n->retro; vertici (f, retro->valore, riga, dim); (void) sscanf (riga, "%*i %i %i %i %i", &da[0], &da[1], &da[2], &da[3]); vertici (f, n->valore, riga, dim); (void) sscanf (riga, "%*i %i %i %i %i", &a[0], &a[1], &a[2], &a[3]); a[2] /= 2; fseek (f, (long) 0, SEEK_END); if (retro->sx == n) (void) fprintf (f, "%i %i %i %i %i %i\n", frsx, a[0] + a[2], a[1] + a[3], da[0] - (a[0] + a[2]), altfr, curv); else (void) fprintf (f, "%i %i %i %i %i %i\n", frdx, da[0] + da[2], da[1], a[0] + a[2] - (da[0] + da[2]), altfr, curv); fclose (f); } arco (n->dx, fn); } free ((void *) riga); } #endif int between (int inf, int valore, int sup) { if (valore < inf) return (inf); if (valore > sup) return (sup); return (valore); } nodo cancella (nodo n, int valore) { unsigned int destra, sinistra; int isempty (nodo); nodo local, pred, retro, succ; nodo predecessore (nodo, int), ricerca (nodo, int); local = ricerca (n, valore); sinistra = isempty (local->sx) == True; destra = isempty (local->dx) == True; /* foglia */ if (sinistra && destra) { if (isempty (local->retro) == True) return ((nodo) NULL); retro = local->retro; if (retro->sx == local) retro->sx = (nodo) NULL; else retro->dx = (nodo) NULL; return (n); } /* 1 sottoalbero */ if (sinistra ^ destra) { succ = sinistra ? local->dx : local->sx; retro = local->retro; if (isempty (retro) == True) { succ->retro = (nodo) NULL; return (succ); } if (retro->sx == local) retro->sx = succ; else retro->dx = succ; return (n); } /* 2 sottoalberi */ pred = predecessore (n, valore); if (local->sx == pred) local->sx = (nodo) NULL; local->valore = pred->valore; retro = pred->retro; if (retro->sx == pred) retro->sx = (nodo) NULL; else if (retro->dx == pred) retro->dx = (nodo) NULL; return (n); } #ifdef STAMPA void disegna (nodo n, int livello, FILE *f, int maxord, int *asc) { int isempty (nodo); if (isempty (n) == False) { disegna (n->sx, livello + 1, f, maxord, asc); (void) fprintf (f, "%i %i %i %i %i %i :%i\n", box, *asc * (basebox + trabox), (maxord - 1 - livello) * altbox, basebox, altbox, curv, n->valore); *asc += 1; disegna (n->dx, livello + 1, f, maxord, asc); } } #endif void insert (nodo *n, int valore, nodo provenienza) { int between (int, int, int), isempty (nodo); if (isempty (*n) == True) { /* nuovo nodo */ *n = (nodo) malloc (sizeof (struct foglia)); (*n)->sx = (nodo) NULL; (*n)->valore = valore; (*n)->retro = provenienza; (*n)->dx = (nodo) NULL; } else { switch (between (-1, valore - (*n)->valore, +1)) { case -1: /* piu' piccolo - inserisci a sinistra */ insert (&((*n)->sx), valore, *n); break; case 0: /* duplicato */ break; case +1: /* piu' grande - inserisci a destra */ insert (&((*n)->dx), valore, *n); break; } } } int isempty (nodo n) { if (n == (nodo) NULL) return (True); else return (False); } #ifdef STAMPA void level (nodo n, int livello, int *maxord) { int isempty (nodo); if (isempty (n) == False) { if (livello > *maxord) *maxord = livello; level (n->sx, livello + 1, maxord); level (n->dx, livello + 1, maxord); } } #endif nodo Massimo (nodo n) { int isempty (nodo); if (isempty (n) == True) longjmp (restore, 0); if (isempty (n->dx) == False) return (Massimo (n->dx)); return (n); } #ifdef STAMPA void maxbox (nodo n, int *maxasc) { int isempty (nodo); if (isempty (n) == False) { maxbox (n->sx, maxasc); *maxasc += 1; maxbox (n->dx, maxasc); } } #endif nodo minimo (nodo n) { int isempty (nodo); if (isempty (n) == True) longjmp (restore, 0); if (isempty (n->sx) == False) return (minimo (n->sx)); return (n); } nodo predecessore (nodo n, int valore) { extern int isempty (nodo); nodo local, tmp; extern nodo Massimo (nodo), minimo (nodo), ricerca (nodo, int); local = ricerca (n, valore); if (isempty (local->sx) == False) return (Massimo (local->sx)); if (local == minimo (n)) longjmp (restore, 0); tmp = local->retro; while (isempty (tmp) == False && local == tmp->sx) { local = tmp; tmp = local->retro; } return (tmp); } nodo ricerca (nodo n, int valore) { extern int between (int, int, int), isempty (nodo); nodo tmp; if (isempty (n) == True) longjmp (restore, 0); tmp = n; switch (between (-1, valore - n->valore, +1)) { case -1: /* piu' piccolo - cerca a sinistra */ tmp = (ricerca (n->sx, valore)); break; case 0: /* trovato */ break; case +1: /* piu' grande - cerca a destra */ tmp = (ricerca (n->dx, valore)); break; } return (tmp); } #ifdef STAMPA void stampa (nodo n) { char fn[L_tmpnam]; FILE *f; int maxasc, maxord; void arco (nodo, char *), maxbox (nodo, int *), disegna (nodo, int, FILE *, int, int *), level (nodo, int, int *); (void) sprintf (fn, "%s", __FILE__); (void) strcpy (strrchr (fn, '.'), ".txt"); remove (fn); if (isempty (n) == True) longjmp (restore, 0); if ((f = fopen (fn, "w")) == NULL) { (void) fprintf (stderr, "errore apertura %s\n", fn); exit (EXIT_FAILURE); } maxasc = maxord = 0; level (n, 1, &maxord); maxbox (n, &maxasc); (void) fprintf (f, "%i %i\n", maxasc * (basebox + trabox) - trabox, maxord * altbox); (void) fprintf (f, "albero\n"); (void) fprintf (f, "Diagramma albero\n"); maxasc = 0; disegna (n, 0, f, maxord, &maxasc); fclose (f); arco (n, fn); } void vertici (FILE *f, int kiave, char *ombra, int dim) { char *p, *riga; int ind; riga = (char *) malloc ((unsigned int) dim); fseek (f, (long) 0, SEEK_SET); (void) fgets (riga, dim, f); while (! feof (f)) { riga[strlen (riga) - 1] = '\0'; (void) strcpy (ombra, riga); p = strtok (riga, " "); if (atoi (p) == box) { for (ind = 0; ind < 6; ind++) p = strtok ((char *) NULL, " "); if (atoi (++p) == kiave) break; } (void) fgets (riga, dim, f); } free ((void *) riga); } #endif void visita (nodo n, int offset) { int incr, ind, isempty (nodo); incr = 2; if (isempty (n) == False) { visita (n->sx, offset + incr); for (ind = 0; ind < offset; ind++) (void) printf (" "); (void) printf ("%*i\n", incr, n->valore); visita (n->dx, offset + incr); } } int albero (void) /* main program */ { char *menu, *oper[] = { "[c]ancella ", "[f]ine ", "[i]nserisci ", "[v]isita " #ifdef STAMPA , "[s]tampa " #endif }; int fine, ind, jump, nop, op, valore; nodo n, cancella (nodo, int); void insert (nodo *, int, nodo); #ifdef STAMPA void stampa (nodo); #endif void visita (nodo, int); valore = 0; nop = sizeof oper / sizeof oper[0]; for (ind = 0; ind < nop; ind++) valore += strlen (oper[ind]); menu = (char *) malloc (valore); bzero (menu, valore); for (ind = 0; ind < nop; ind++) (void) strcat (menu, oper[ind]); fine = True; n = (nodo) NULL; /* inizializzazione albero */ jump = setjmp (restore); /* punto di ritorno */ if (jump) (void) getchar (); do { (void) printf ("%s", menu); (void) printf ("> "); op = fgetc (stdin); switch (op) { default: /* errore */ (void) printf ("\noperazioni ammesse: "); (void) printf ("%s\n\n", menu); break; case 'c': /* cancellazione */ (void) fscanf (stdin, "%i", &valore); n = cancella (n, valore); break; case 'f': /* fine */ fine = False; break; case 'i': /* inserzione */ (void) fscanf (stdin, "%i", &valore); insert (&n, valore, (nodo) NULL); break; #ifdef STAMPA case 's': /* stampa */ stampa (n); break; #endif case 'v': /* visita */ visita (n, 0); break; } (void) getchar (); } while (fine == True); free ((void *) menu); exit (EXIT_SUCCESS); }