Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 18
  1. #1
    Utente di HTML.it L'avatar di caralu
    Registrato dal
    Sep 2004
    Messaggi
    135

    [c] Risoluzione Problema Algoritmo

    SCUSATE MA HO SBAGLIATO IL TITOLO NELL'ALTRO MESSAGGIO!
    Salve a tutti!
    Ho un grosso problema: Dovrei risolvere il seguente algoritmo in linguaggio C :
    ****************************************
    ****************************
    "Gli studiosi di testi letterari a volte fanno un esame statistico delle
    lettere (A,B,..), articoli (Il, lo,...),preposizioni(di, del, al...) e
    parole presenti in un certo testo. Scrivere un programma che faccia
    questa analisi stampando per ciascun di questi elementi le percentuali
    di occorrenza in ordine crescente. Come esempi si prendano testi a
    carattere matematico, informatico, un aricolo di giornale sportivo, un
    racconto di uno scrittore".
    ****************************************
    *****************************
    Ho provato ad implementarlo da un pò di tempo ma non riesco a trovare l'errore che c'è (presumo) nella funzione pmatch: l'istruzione j = insuccesso[j-1]+1; viene ripetuta all'infinito. Inoltre la funzione confronta_stringa effettua la sua analisi solo con un elemento della lista anzichè con tutti gli elementi. C'E' QUALCUNO CHE RIESCE A TROVARE GLI ERRORI????
    IL CODICE DA ME IMPLEMENTATO E' IL SEGUENTE:

    //-------------------------------------------------------------------

    #include <stdio.h>
    #include <malloc.h>
    #include <stdlib.h>
    #include <string.h>
    #include <conio.h>

    #define tot_lettere 36 /*Tutte le lettere dell'alfabeto + i numeri del sistema decimale*/
    #define dim_max 100

    struct lista{
    char *parola;
    int contatore;
    struct lista *next;
    };

    typedef struct lista list;

    void spazio (void);
    void analisi(char *);
    int pmatch(char *, char *);
    void insucc(char *);
    void incrementa_lettera(char );
    list *crea_lista(list *, char *);
    list *confronta_stringa(char *, list *);
    void stampa(list *);

    int insuccesso[dim_max];
    char lettere[tot_lettere]; /*array contenente tutte le lettere dell'alfabeto + num.del sist decimale*/
    char max_parola[dim_max]; //Parola massima composta da 25 caratteri
    char pat[dim_max];

    main()
    {
    int s, i;
    char *testo;

    do
    {
    spazio();
    printf("\t\tDIGITI:\n\n");
    printf("\n1- Analizzare il testo esistente (che verrà visualizzato)\n2- Inserire un nuovo testo\n0- ESCI dal programma");
    spazio();
    scanf("%d",& s);

    switch (s){

    case 1 : clrscr();
    spazio();
    printf("Il testo esistente e':");
    spazio();
    //80 caratteri per riga nella schermata dell'applicativo
    printf("\nDurante i primi decenni della loro esistenza, le reti di computer sono state\nusate principalmente dai ricercatori universitari per inviare messaggi\nelettronici, e dai dipendenti di industrie per condividere stampanti.\nIn questi ambiti, la segretezza non aveva ragione di esistere.\nInvece adesso, con milioni di comuni cittadini che utilizzano le reti per\noperazioni bancarie, commerciali e fiscali questo problema e' apparso\nell orizzonte come potenzialmente collettivo.\nLa sicurezza in rete e' un argomento vasto e riguarda una moltitudine di\ncrimini.\nNella sua forma piu' semplice, si occupa di assicurare che nessuno possa leggere\no, peggio ancora, modificare i messaggi destinati ad altri. Si occupa di persone\nche cercano di accedere a servizi remoti che non sono autorizzati a usare.\nLa sicurezza si occupa anche di problemi come l intercettazione di messaggi\nautografi e la loro riproduzione, e di persone che cercano di negare di aver\nspedito tali messaggi.\n");
    spazio();
    testo = "\nDurante i primi decenni della loro esistenza, le reti di computer sono state\nusate principalmente dai ricercatori universitari per inviare messaggi\nelettronici, e dai dipendenti di industrie per condividere stampanti.\nIn questi ambiti, la segretezza non aveva ragione di esistere.\nInvece adesso, con milioni di comuni cittadini che utilizzano le reti per\noperazioni bancarie, commerciali e fiscali questo problema e' apparso\nell orizzonte come potenzialmente collettivo.\nLa sicurezza in rete e' un argomento vasto e riguarda una moltitudine di\ncrimini.\nNella sua forma piu' semplice, si occupa di assicurare che nessuno possa leggere\no, peggio ancora, modificare i messaggi destinati ad altri. Si occupa di persone\nche cercano di accedere a servizi remoti che non sono autorizzati a usare.\nLa sicurezza si occupa anche di problemi come l intercettazione di messaggi\nautografi e la loro riproduzione, e di persone che cercano di negare di aver\nspedito tali messaggi.\n ";
    printf("\n\n\n\t\t...[INVIO] per continuare...\n");
    getchar(); getchar();
    clrscr();
    analisi(testo);

    for(i=0; i<tot_lettere; i++)
    printf("\n%d lettera : %d ", i+1, lettere[i]);
    break;

    case 2 : //clrscr();
    spazio();
    printf("\tINSERISCA UN NUOVO TESTO, tutto su una riga ([INVIO] per terminare):");
    gets(testo);
    //clrscr();
    spazio();
    printf("\t\tHA INSERITO:");
    spazio();
    puts(testo);
    spazio();
    printf("\n\n\n\t\t...[INVIO] per continuare...\n");
    getchar();
    //clrscr();
    analisi(testo);
    break;

    case 0 : exit(0);

    default : //clrscr();
    printf("\a\t\tSELEZIONE NON PRESENTE!\n\n\t\tDigiti [INVIO] e ripeta la scelta:");
    getchar();
    break;
    }
    }
    while(s < 0 || s > 2);


    fflush(stdin);
    getchar();
    }

    // ****************************************
    ***************************

    void spazio(void)
    {
    printf("\n-----------------------------------------------------\n);
    }

    // ****************************************
    ***************************

    void analisi (char *testo)
    {
    int cont = 0, i;
    list *inizio, *p;

    inizio = p = NULL;

    do
    {
    /*Se la lettera corrente è uguale ad un qualsiasi carattere di punteggiatura si effettua la verifica*/
    if(*testo != ',' && *testo != '.' && *testo != ' ' && *testo != '?' && *testo != '!' && *testo != '"' && *testo != '=' && *testo != '\' && *testo != ':' && *testo != '<' && *testo != '>' && *testo != ';' && *testo != '£' && *testo != '$' && *testo != '%' && *testo != '(' && *testo != ')' && *testo != '*' && *testo != '_' && *testo != '+' && *testo != '-' && *testo != '/' && *testo != '|' && *testo != '#' && *testo != '@' && *testo != '[' && *testo != ']' && *testo != ''')
    {
    incrementa_lettera(*testo); //Incrementa il contatore della lettera

    max_parola[cont] = *testo;

    cont++;
    testo++;
    }
    else
    {
    if (cont == 0 || cont ==1) /*Se è una lettera il suo contatore è già stato incrementato*/
    {
    testo++;
    cont = 0;
    }
    else
    {
    inizio = confronta_stringa(max_parola, inizio);
    cont = 0;
    }

    for(i=0; i<tot_lettere; i++) /*Inizializziamo a vuoto tutte le componenti dell'array*/
    max_parola[i] = '\0';
    }

    }
    while(*testo != '\0');

    stampa(p);
    }

    // ****************************************
    ***************************

    list *confronta_stringa(char *v, list *inizio)
    {
    int flag = -1;

    while(inizio && flag == -1) /*non si è raggiunta la fine del testo e non si è trovata la stringa*/
    {
    flag = pmatch(v, inizio->parola);
    if(flag != -1) /*Se il pattern non è stato trovato pmatch restituisce -1 */
    {
    inizio->contatore ++; /*Incrementa il contatore della stringa esistente*/
    return(inizio);
    }
    else
    inizio = inizio->next;
    }

    if(flag == -1)
    inizio = crea_lista(inizio, v);

    return(inizio);
    }

    // ****************************************
    ***************************

    int pmatch(char *stringa, char *pat)
    {
    int i=0, j=0;

    int lens = strlen(stringa);
    int lenp = strlen(pat);

    while(i<lens && j<lenp)
    {
    if(stringa[i] == pat[j])
    {i++; j++;}
    else
    if(j==0)
    i++;
    else
    j = insuccesso[j-1]+1;
    }
    return( (j==lenp) ? (i-lenp) : -1);
    }


    // ****************************************
    ***************************

    list *crea_lista(list *inizio, char *pattern)
    {
    list *p;

    p = (list *)malloc(sizeof(list));

    strcpy(p->parola, pattern);
    p->contatore = 1;
    p->next = inizio;

    return(p);
    }

    // ****************************************
    ***************************

    void stampa (list *inizio)
    {
    spazio();
    printf("\t\tCOMPOSIZIONE TESTO:");
    spazio();

    while(inizio)
    {
    printf("\n%s compare nel testo %d volte.", inizio->parola, inizio->contatore);
    inizio = inizio->next;
    }
    spazio();
    }

    // ****************************************
    ***************************

    void incrementa_lettera(char lettera)
    {
    switch (lettera){
    case 'a' :
    case 'A' : lettere[0]++; break;
    case 'b' :
    case 'B' : lettere[1]++; break;
    case 'c' :
    case 'C' : lettere[2]++; break;
    case 'd' :
    case 'D' : lettere[3]++; break;
    case 'e' :
    case 'E' : lettere[4]++; break;
    case 'f' :
    case 'F' : lettere[5]++; break;
    case 'g' :
    case 'G' : lettere[6]++; break;
    case 'h' :
    case 'H' : lettere[7]++; break;
    case 'i' :
    case 'I' : lettere[8]++; break;
    case 'j' :
    case 'J' : lettere[9]++; break;
    case 'k' :
    case 'K' : lettere[10]++; break;
    case 'l' :
    case 'L' : lettere[11]++; break;
    case 'm' :
    case 'M' : lettere[12]++; break;
    case 'n' :
    case 'N' : lettere[13]++; break;
    case 'o' :
    case 'O' : lettere[14]++; break;
    case 'p' :
    case 'P' : lettere[15]++; break;
    case 'q' :
    case 'Q' : lettere[16]++; break;
    case 'r' :
    case 'R' : lettere[17]++; break;
    case 's' :
    case 'S' : lettere[18]++; break;
    case 't' :
    case 'T' : lettere[19]++; break;
    case 'u' :
    case 'U' : lettere[20]++; break;
    case 'v' :
    case 'V' : lettere[21]++; break;
    case 'w' :
    case 'W' : lettere[22]++; break;
    case 'x' :
    case 'X' : lettere[23]++; break;
    case 'y' :
    case 'Y' : lettere[24]++; break;
    case 'z' :
    case 'Z' : lettere[25]++; break;
    case '1' : lettere[26]++; break;
    case '2' : lettere[27]++; break;
    case '3' : lettere[28]++; break;
    case '4' : lettere[29]++; break;
    case '5' : lettere[30]++; break;
    case '6' : lettere[31]++; break;
    case '7' : lettere[32]++; break;
    case '8' : lettere[33]++; break;
    case '9' : lettere[34]++; break;
    case '0' : lettere[35]++; break;

    default : break;
    }
    }

  2. #2
    Utente di HTML.it L'avatar di anx721
    Registrato dal
    Apr 2003
    Messaggi
    2,352
    Se vuoi una mano:

    1 - Spiega a parole come hai risolto il problema: che struttura dati utilizzi e come si svolge la computazione;

    2 - Inserisci commenti per spieare cosa fa ogni funzione;

    3 - Posta solo il codice che effettua la computazione, con la definizione dei tipi, evitando tutto il codice per l'input e l'output;

    4 - usa il pulsante code per indentare il codece.

    Sun Certified Java Programmer

    EUCIP Core Level Certified

    European Certification of Informatics Professionals

  3. #3
    Utente di HTML.it L'avatar di caralu
    Registrato dal
    Sep 2004
    Messaggi
    135

    IL MIO RAGIONAMENTO....

    Per il programma ho implementato una struttura di questo tipo:

    Visto che su un intero testo dobbiamo analizzare lettere, articoli, preposizioni e parole (stampando per ciascuno di essi le percentuali di occorrenza...) ho separato l'analisi delle singole lettere dall'analisi delle parole, aricoli e preposizioni, creando un'array di grandezza pari a tutte le lettere dell'alfabeto + i numeri del sistema decimale (l'analisi può essere fatta anche su testi di carattere scientifico) che è lettere[tot_lettere] .
    Si effettua una scansione di tutto il testo e si memorizzano le lettere nell'array "lettere"; le parole, gli articoli e le preposizioni vengono memorizzate in una lista concatenata se non sono già presenti in questa, altrimenti viene incrementato il rispettivo contatore.
    Arrivato alla fine del testo dovrei stampare tutta la lista memorizzata(con le percentuali di occorrenza di ogni elemento) e l'array di caratteri (anche questo con le percentuali di occorrenza).
    Per fare tutto ciò ho impostato il seguente codice:
    - Nel "main()" con uno switch case si sceglie se si vuole utilizzare un testo pre-inserito per fare l'analisi, oppure se si vuole inserire un nuovo testo; In entrambe i casi viene chiamata la funzione principale "analisi" che dovrebbe svolgere il seguente compito:

    codice:
    //
    //-------------------------------------------------------------------
    //- FUNZIONE analisi():
    
    void analisi (char *testo)
      {
        int cont = 0, i;
        list *inizio, *p;
    
        inizio = p = NULL;
    
          do
            {
        /*controllo se il carattere corrente è un simbolo di  punteggiatura o una lettera: */
    
          if (*testo != ',' && *testo != '.' && *testo != ' ' && *testo != '?' && *testo != '!' && *testo != '"' && *testo != '=' && *testo != '\\' && *testo != ':' && *testo != '<' && *testo != '>' && *testo != ';' && *testo != '£' && *testo != '$' && *testo != '%' && *testo != '(' && *testo != ')' && *testo != '*' && *testo != '_' && *testo != '+' && *testo != '-' && *testo != '/' && *testo != '|' && *testo != '#' && *testo != '@' && *testo != '[' && *testo != ']' && *testo != '\'')
            {
    	//Se è una lettera eseguo gli incrementi:
    
              incrementa_lettera(*testo); /*incrementa il contatore della lettera corrente*/
    
              max_parola[cont] = *testo;  /*memorizza la lettera corrente nell'array*/
    
              cont++; /*Incremento il contatore di max_parola in modo da poter capire se è una lettera (cont == 1) o una parola, articolo, una 			preposizione (cont>1)*/
    
              testo++; //vado alla lettera successiva
    
    	/*Questa parte di codice viene eseguita fino a che non si raggiunge un carattere di punteggiatura, ciò significa che si è 		raggiunta la fine della parola (o dell'articolo, preposizione, ecc..) o è una lettera*/
            }
          else
            {    /*Se il contatore di è una lettera il suo contatore è già stato incrementato*/
              if (cont == 0 || cont ==1)  
                { /*se è vera la condizione nell' if allora il carattere era una lettera (il suo contatore è già stato incrementato)*/
                  testo++;  //Quindi andiamo al carattere successivo
                  cont = 0;  //Reinizializziamo il contatore a zero
                }
              else
                {  /*Se è una parola (articolo, ecc...) allora eseguo la funzione confronta_stringa*/
              inizio = confronta_stringa(max_parola,inizio); /*Controlla se la stringa è presente nella lista concatenata, altrimenti la memorizza; se la stringa è già presente incrementa il suo contatore*/
                cont = 0;  //Reinizializziamo il contatore a zero
                }
    /*Inizializziamo a vuoto tutte le componenti dell'array in modo da poter riscrivere eventualmente una parola più corta della precedente*/
                for(i=0; i<tot_lettere; i++)
    		max_parola[i] = '\0';		
            }
    
         }
         while(*testo != '\0');  /*esegue questa funzione fino a che il testo non è finito*/
    
    	stampa(p);  /*stampa la lista di parole, articoli, ecc.. con la loro percentuale di occorrenza*/
      } 
    
    //-------------------------------------------------------------------
    //- FUNZIONE "confronta_stringa()":
    
    list *confronta_stringa(char *v, list *inizio)
      {
        int flag = -1;  /*Inizializziamo la nostra variabile "segnale" a -1 */
    
        while(inizio && flag == -1) 	/*non si è raggiunta la fine del testo (inizio!=0) e non si è trovata la stringa flag == -1 */
          {
          flag = pmatch(v, inizio->parola);  /*confronta la stringa v con la prima stringa della lista.Se la stringa non viene trovata restituisce -1*/
              if(flag != -1)   //Se il pattern è stato trovato:
                {
                  inizio->contatore ++; /*Incrementa il contatore della stringa esistente che è già in memoria nella lista concatenata*/
                  return(inizio);
                }
              else
                inizio = inizio->next;  /* scorre la lista all'elemento successivo visto che la stringa è diversa dall'elemento corrente della lista*/
          }
    
      if(flag == -1)  /* se la stringa non è presente nella lista allora la memorizza nella coda */
        inizio = crea_lista(inizio, v);
    
      return(inizio);
      }
    
    //-------------------------------------------------------------------
    //- FUNZIONE pmatch:		/*algoritmo di ricerca di un pattern di caratteri idato da Knuth, Morris e Pratt:
    	il ciclo while viene ripetuto finchè non viene raggiunta la fine di una delle due stringhe (stringa e pat). Poichè la variabile i non viene mai diminuita, le righe che aumentano (i) non possono essere eseguite più di m=strlen(stringa) volte. Il ripristino di j a insuccesso[j-1]+1  riduce il valore di j. Pertanto questa operazione non può essere fatta più volte di quanto j non sia incrementato dall'istruzione j++, altrimenti j andrebbe fuori dal limite di pat.  Ogni volta che l'istruzione j++ viene eseguita, j viene incrementato. Pertanto j non può essere incrementato più di m volte. */
    
    int pmatch(char *stringa, char *pat)
    {
      int i=0, j=0;
    
      int lens = strlen(stringa);
      int lenp = strlen(pat);
    
      insucc(pat);  //Inizializza l'array "insuccesso" per ottimizzare l'algoritmo
    
      while(i<lens && j<lenp)
        {
          if(stringa[i] == pat[j])
            {i++; j++;}
          else
            if(j==0)
              i++;
            else
              j = insuccesso[j-1]+1;
        }
        return( (j==lenp) ? (i-lenp) : -1);  /*questa istruzione verifica se pat è stata trovata oppure no. Se pat non è ststa trovata, l'indice j 					non è uguale alla lunghezza di pat e l'istruzione fornisce il valore -1. Se la stringa pat viene 					trovata, allora la posizione di partenza è pari a i meno la lunghezza di pat.*/
    }
    
    //-------------------------------------------------------------------
    FUNZIONE insucc():  /*Calcola la funzione di insuccesso per un pattern di caratteri da ricercare (pat):
    ad ogni iterazione del ciclo while il valore di i diminuisce secondo la definizione di f (descritta sotto). La variabile i viene ripristinata all'inizio di ogni iterazione del ciclo for. Questa variabile può essere impostata a -1 (inizialmente o quando la precedente iterazione del ciclo for passa attrverso la clausola else) oppure ad un valore maggiore di 1 rispetto al suo valore finale nella precedente iterazione (cioè quando viene eseguita l'istruzione "insuccesso[j] = i+1"). */
    
    void insucc(char *pat)
    {
      int i, j;
    
      int n = strlen(pat);
    
      insuccesso[0] = -1;
    
      for(j=1; j<n; j++)
        {
          i = insuccesso[j-1];
          while((pat[j] != pat[i+1]) && (i>=0))
            i = insuccesso[i];
    
          if(pat[j] == pat[i+1])
              insuccesso[j] = i+1;
          else
              insuccesso[j] = -1;
        }
    }

  4. #4
    Utente di HTML.it L'avatar di caralu
    Registrato dal
    Sep 2004
    Messaggi
    135

    Dimenticavo

    Scusa, dimenticavo...
    Se non ti è chiaro qualcos'altro fammi sapere così ti do qualche altro dettaglio.
    Grazie per l'interessamento e l'aiuto, a presto

  5. #5
    Utente di HTML.it L'avatar di anx721
    Registrato dal
    Apr 2003
    Messaggi
    2,352
    Ciao,

    purtoppo non riesco a compilare il tuo codice, mi pare che non me lo hai messo completo, manca la definizione del tipo list e poi c'è qualke errore. Ad esempio con '\' non indichi il carattere backslash, che si indica con '\\'; in enerale, nei caratteri e nelle strinhe, la presenza di un backslash serve a indicare caratteri speciali, ad esempio con '\t' si indica il carattere di tabulazione, con '\n' il carattere di 'a capo'. Poi non mi piace il fatto che confronti esplicitamente un carattere con tutti i caratteri alfabetici e non per verificare se si trata di una lettere, di un numero o di altro: esisteono appostite funzioni di libreira per fare questo.


    Qui di seguito ti dò la mia versione, che si basa su delle precise considerazioni.


    Importante è definire cosa deve essere consiferata una 'parola' nel testo. Io scelgo una definizione semplice, ovvero una parola è una qlsiasi sequenza di caratteri e numeri, visto che l'esercizio richiede di analizzare la presenza di caratteri e numeri.

    Cosi ad esempio:

    1 - 'ciao' è una parola
    2 - '2004'è una parola
    3 - 'a1' è una parola
    4 - a&5 non è una parola perchè c'è il simbolo '&'

    Individuare dei numeri in un testo non è semplicissimo; ad esempio in un testo scientifico si potrebbe scrivere un numero come: 0.5 (zero virgola 5); ma se incontri il testo '0.5' non puo isapere a priori se si tratta del numero 0.5 oppure lo zero è l'ultima parola di una frase, poi c'è il punto che conclude la frase, e poi il 5 è la prima parola della frase successiva. Analoga considerazione vale per espressioni tipo: 10,2. Inoltre i numeri possono anche essere neativi, così -3.5 dovrebbe essere considerato un numero, pssono essere espressi in forma scientifica come 0.3E2, ecc ecc... Per poter individuare con esattezza un numero in un testo è necessario che il testo rispetti una precisa grammatica, in modo tale che dal contesto in cui si trova il numero si puo capire se 0.5 è un numero oppure il punto indica la fine di una frase. Difatti tutti i linguaggi di programmazione sono definiti tramite grammatiche, per cui in un programma puoi scrivere numeri senza ambiguità Cìò non è vero per un testo qlsiasi, in cui solo un lettore 'umano' o comuqnue intelligente puo indivinare se si tratta del numero 0.5 o dellla fine di una frase.

    Proprio per questo la mia scelta è di considerare terminato un numero quando si incontrano simboli che non siano cifre.

    Un'altra scelta fatta è di considerare come una parola una sequenza unita di numeri e lettere, cosi ad esempio 'a2' è una parola, 'anno2004' è un'altra parola: non è raro infatto in testi scientifici trovare termini che contengono numeri e lettere insieme.

    Unendo queste cosndiderazioni insieme si giunge alla semplice definizione che avevo dato all'inizio ovvero:

    Una parola è una sequenza di lettere e numeri.

    Questa definizione rende particolarmente semplice individuare le parole all'interno del testo: appena si incontra una lettera o un numero significa che sta iniziando una parola; quindi si va avanti ficnhe ci sono lettere o numeri, e appena si incontra un carattere che non è nè una lettera nè un numero, la parola corrente è stata individuata.


    Lo schema che ho seguito quindi è il seguente:

    1 - Estrapolo la prossima parola dal testo secondo l definizione di parola che ho dato;
    2 - per ogni carattere nella parola incremento il suo numero di occorrenze;
    3 - inserisco la parola nella lista di parole se non è ancora presente, altrimenti ne incremento le occorrenze.

    Per ottenere la prossima parola da un testo char * ho implementato una funzione:

    char *prossimaParola(char *testo)

    in cui mantengo in una variabile la posizione corrente a cui sono arrivato; quindi vado avanti finchè trovo lettere e numeri; appena trovo un carattere che non è una lettera o un numero significa che ho raggiunto la fine della parola corrente: posso quindi allocarmi un nuovo char * in cui inserire la parola appena trovata e restituirla. Per verificare che un carattere sia una lettera o un numero basta richiamare la funzione di libreria isalnum(c) che restituisce 1 se c è una lettera o un numero, altrimenti resituisce falso.

    Una volta che abbiamo a disposizione questa funzione è tutto molto facile: se infatti 'testo' contiene il testo da analizzare basta richimare prossimaParola(testo) per ottenere la prossima parola:

    char *parola = prossimaParola(testo);

    Quindi possiamo aggiornare le frequenze dei caratteri e dei numeri contenuti nella stringa 'parola': basta scorrerla posizione per posizione.

    Per mantenere la lista delle parole ho definito una struct con un campo char * che mantiene la stringa, un campo frequenza che mantiene il numero di occorrenze, e un puntatore all'elemento successivo. La variabile globale 'parole', inizialmente pari a NULL, mantiene la lista di parole trovate.

    Quindi ogni parola estratta la aggiungiamo alla lista; per questo c'è una funzione

    void inserisciParola(char *parola);

    che verifica se la parola è gia presente o meno nella lista 'parole', creando eventualemtne un nuovo elemento, altrimenti si limita ad incrementare il numero di occorrenze.

    Supponendo che il testo si trovi nella variabile 'testo', il main non fa altro che estrarre una parola p con p = prossimaParola(testo), aggiornare la frequenza con aggiornaFrequenze(p), e inserirle nella lista con inserisciParola(p):

    while((p = prossimaParola(testo))){
    aggiornaFrequenze(p);
    inserisciParola(p);
    }

    il tutto finchè prossimaParola(testo) non ritorna NULL, il che significa che non ci sono piu parole.

    A questo punto hai la lista di parole con le relative occorrenze. Il codice che ho scritto si ferma qua.

    Per poter stampare la lista ordinata, ti consiglio di memroizzarri in un array i puntatori agli elementi della lista, poi ordini l'array in base alle occorrenze. Per stampare la frequenza ti basta dividere il numero di occorrenze di ogni parola per il numero di parole totali, mantentuo in una variabile globale; lo stesso per la frequenza delle singole lettere o numeri. Un'altra cosa di cui occuparsi è come inserire il testo da analizzare nella variabile testo; lo puoi leggere da un file o farlo inserire all'utente dall'input. Il codice nel prossimo post.

    Sun Certified Java Programmer

    EUCIP Core Level Certified

    European Certification of Informatics Professionals

  6. #6
    Utente di HTML.it L'avatar di anx721
    Registrato dal
    Apr 2003
    Messaggi
    2,352
    Il codice è abbastanza commentato, quindi si dovrebbe capire facilmnte. PS: ho fatto qlcke prova e mi pare funzioni, ma non posso esserne sicuro al 100%, se sei interessato fai qlke prova tu ed eventualmente fammi sapere se trovi errori ;)

    codice:
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    
    
    //Mantiene le frequenze delle lettere
    int freqLettere['z' - 'a'];
    //Mantiene le frequenze dei numeri
    int freqNumeri[10];
    //Mantiene il numero totale di caratteri trovati nel testo
    //(lettere e numeri)
    int totaleCaratteri = 0;
    //Mantiene il numero totale di parole trovate nel testo
    int totaleParole = 0;
    
    
    //Definizione dell'elemento di una lista
    typedef struct lista{
    	char *parola;
    	int frequenza;
    	lista *next;
    } lista;
    
    //Variabile che mantiene le lista di parole
    lista *parole = NULL;
    
    //Inizializza a zero i vettori delle frequenze
    void inizializza(){
    	int i;
    	for(i = 0; i < 10; i++)
    		freqNumeri[i] = 0;
    	for(i = 0; i < ('z' - 'a'); i++)
    		freqLettere[i] = 0;
    }
    
    //Aggiorna le frequenze di lettere e numeri
    void aggiornaFrequenze(char *parola){
    	int i;
    	char c;
    	int len = strlen(parola);
    	for(i =  0; i < len; i++){
    		c = parola[i];
    		//Se è una lettera
    		if(isalpha(c)){
    			//rendiamo tutte le lettere minuscole
    			c = tolower(c);
    			//incrementiamo la posizione corrispondente di freqLettere
    			freqLettere[c - 'a']++;
    		}
    		//Se è un numero
    		if(isdigit(c)){
    			//incrementiamo la posizione corrispondente di freqLettere
    			freqNumeri[c - '0']++;
    		}
    	}
    	//Incremento il numero di parole totali
    	totaleParole++;
    	//Incremento il numero di caratteri totali
    	totaleCaratteri = totaleCaratteri + len;
    }
    
    //Restituisce la prossima parola che si trova in testo a partire
    //dalla posizione posizioneCorrente. Una parola è definita come
    //una sequenza di lettere e/o numeri senza altri caratteri.
    //Restituisce NULL se non c'è una prossima parola
    char *prossimaParola(char *testo){
    	static int posizioneCorrente = 0;
    	int i;
    	int len = strlen(testo);
    	//mi sposto avanti finche non trovo una lettera o un numero
    	while(! isalnum(testo[posizioneCorrente])){
    		posizioneCorrente++;
    		//se iuno alla fine senza aver trovato lettere o numeri
    		//ritorno null
    		if(posizioneCorrente >= len)
    			return NULL;
    	}
    	//incremento i finchè trovo numeri e lettere; alla fine del cilco
    	//i punta alla fine della parola corrente
    	i = posizioneCorrente;
    	while(isalnum(testo[i]) && (i < len))
    		i++;
    	int lunghezza = i - posizioneCorrente;
    	char *parola = (char *)malloc((lunghezza + 1));
    	for(i = 0; i <= lunghezza; i++)
    		parola[i] = testo[posizioneCorrente + i];
    	//Inserisco il carattere di fine stringa alla fine della parola
    	parola[lunghezza] = '\0';
    	posizioneCorrente = posizioneCorrente + i;
    	return parola;
    }
    
    void stampaNumeri(){
    	printf("\n\n");
    	int i;
    	for(i = 0; i < 10; i++)
    		printf("\nfrequenza di %d: %d", i, freqNumeri[i]);
    }
    
    void stampaLettere(){
    	printf("\n\n");
    	int i;
    	for(i = 0; i < ('z' - 'a'); i++)
    		printf("\nfrequenza di %c: %d", 'a' + i, freqLettere[i]);
    }
    
    void stampaParole(){
    	printf("\n\n");
    	lista *temp = parole;
    	while(temp){
    		printf("\nfrequenza di %s: %d", temp -> parola, temp -> frequenza);
    		temp = temp -> next;
    	}
    }
    
    //Inserisce la parola nella lista parole, se non è gia presente,
    //altrimenti incrementa la sua frequenza
    void inserisciParola(char *parola){
    	lista *temp = parole;
    	//Scorriamo la lista per vedere se la parola è ia stata inserita
    	while(temp){
    		//Se la parola già c'è ci limitiamo a incrementare
    		//la frequenza
    		if(strcmp(temp -> parola, parola) == 0){
    			temp -> frequenza++;
    			return;
    		}
    		temp = temp -> next;
    	}
    	//Se la parola non è stata trovata, creiamo un nuovo elemento
    	//che sarà inserito in testa alla lista.
    	temp = (lista *)malloc(sizeof(lista));
    	temp -> parola = parola;
    	temp -> frequenza = 1;
    	temp -> next = parole;
    	//Facciamo puntare la lista 'parole' all'elemento di testa
    	//appena isnerito
    	parole = temp;
    }
    
    
    int main(){
    	char * p;
    	char *testo = "ciao\tt\n1r&7 (re)re t";
    	while((p = prossimaParola(testo))){
    		aggiornaFrequenze(p);
    		inserisciParola(p);
    	}
    	stampaNumeri();
    	stampaLettere();
    	stampaParole();
    	
    	printf("\n\nTotale parole: %d", totaleParole);
    	printf("\n\nTotale caratteri: %d", totaleCaratteri);
    	return 0;
    }

    Sun Certified Java Programmer

    EUCIP Core Level Certified

    European Certification of Informatics Professionals

  7. #7
    Utente di HTML.it L'avatar di anx721
    Registrato dal
    Apr 2003
    Messaggi
    2,352
    Ho corretto un piccolo errore sui cicli che non mi faceva considerare la lettera z:

    codice:
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    
    
    //Mantiene le frequenze delle lettere
    int freqLettere['z' - 'a' + 1];
    //Mantiene le frequenze dei numeri
    int freqNumeri[10];
    //Mantiene il numero totale di caratteri trovati nel testo
    //(lettere e numeri)
    int totaleCaratteri = 0;
    //Mantiene il numero totale di parole trovate nel testo
    int totaleParole = 0;
    
    
    //Definizione dell'elemento di una lista
    typedef struct lista{
    	char *parola;
    	int frequenza;
    	lista *next;
    } lista;
    
    //Variabile che mantiene le lista di parole
    lista *parole = NULL;
    
    //Inizializza a zero i vettori delle frequenze
    void inizializza(){
    	int i;
    	for(i = 0; i < 10; i++)
    		freqNumeri[i] = 0;
    	for(i = 0; i < ('z' - 'a' + 1); i++)
    		freqLettere[i] = 0;
    }
    
    //Aggiorna le frequenze di lettere e numeri
    void aggiornaFrequenze(char *parola){
    	int i;
    	char c;
    	int len = strlen(parola);
    	for(i =  0; i < len; i++){
    		c = parola[i];
    		//Se è una lettera
    		if(isalpha(c)){
    			//rendiamo tutte le lettere minuscole
    			c = tolower(c);
    			//incrementiamo la posizione corrispondente di freqLettere
    			freqLettere[c - 'a']++;
    		}
    		//Se è un numero
    		if(isdigit(c)){
    			//incrementiamo la posizione corrispondente di freqLettere
    			freqNumeri[c - '0']++;
    		}
    	}
    	//Incremento il numero di parole totali
    	totaleParole++;
    	//Incremento il numero di caratteri totali
    	totaleCaratteri = totaleCaratteri + len;
    }
    
    //Restituisce la prossima parola che si trova in testo a partire
    //dalla posizione posizioneCorrente. Una parola è definita come
    //una sequenza di lettere e/o numeri senza altri caratteri.
    //Restituisce NULL se non c'è una prossima parola
    char *prossimaParola(char *testo){
    	static int posizioneCorrente = 0;
    	int i;
    	int len = strlen(testo);
    	//mi sposto avanti finche non trovo una lettera o un numero
    	while(! isalnum(testo[posizioneCorrente])){
    		posizioneCorrente++;
    		//se iuno alla fine senza aver trovato lettere o numeri
    		//ritorno null
    		if(posizioneCorrente >= len)
    			return NULL;
    	}
    	//incremento i finchè trovo numeri e lettere; alla fine del cilco
    	//i punta alla fine della parola corrente
    	i = posizioneCorrente;
    	while(isalnum(testo[i]) && (i < len))
    		i++;
    	int lunghezza = i - posizioneCorrente;
    	char *parola = (char *)malloc((lunghezza + 1));
    	for(i = 0; i <= lunghezza; i++)
    		parola[i] = testo[posizioneCorrente + i];
    	//Inserisco il carattere di fine stringa alla fine della parola
    	parola[lunghezza] = '\0';
    	posizioneCorrente = posizioneCorrente + i;
    	return parola;
    }
    
    void stampaNumeri(){
    	printf("\n\n");
    	int i;
    	for(i = 0; i < 10; i++)
    		printf("\nfrequenza di %d: %d", i, freqNumeri[i]);
    }
    
    void stampaLettere(){
    	printf("\n\n");
    	int i;
    	for(i = 0; i < ('z' - 'a' + 1); i++)
    		printf("\nfrequenza di %c: %d", 'a' + i, freqLettere[i]);
    }
    
    void stampaParole(){
    	printf("\n\n");
    	lista *temp = parole;
    	while(temp){
    		printf("\nfrequenza di %s: %d", temp -> parola, temp -> frequenza);
    		temp = temp -> next;
    	}
    }
    
    //Inserisce la parola nella lista parole, se non è gia presente,
    //altrimenti incrementa la sua frequenza
    void inserisciParola(char *parola){
    	lista *temp = parole;
    	//Scorriamo la lista per vedere se la parola è ia stata inserita
    	while(temp){
    		//Se la parola già c'è ci limitiamo a incrementare
    		//la frequenza
    		if(strcmp(temp -> parola, parola) == 0){
    			temp -> frequenza++;
    			return;
    		}
    		temp = temp -> next;
    	}
    	//Se la parola non è stata trovata, creiamo un nuovo elemento
    	//che sarà inserito in testa alla lista.
    	temp = (lista *)malloc(sizeof(lista));
    	temp -> parola = parola;
    	temp -> frequenza = 1;
    	temp -> next = parole;
    	//Facciamo puntare la lista 'parole' all'elemento di testa
    	//appena isnerito
    	parole = temp;
    }
    
    
    int main(){
    	char * p;
    	char *testo = "ciao\tt\n1r&7 (re)re t zz";
    	while((p = prossimaParola(testo))){
    		aggiornaFrequenze(p);
    		inserisciParola(p);
    	}
    	stampaNumeri();
    	stampaLettere();
    	stampaParole();
    	
    	printf("\n\nTotale parole: %d", totaleParole);
    	printf("\n\nTotale caratteri: %d", totaleCaratteri);
    	return 0;
    }

    Sun Certified Java Programmer

    EUCIP Core Level Certified

    European Certification of Informatics Professionals

  8. #8

    A Carlooooooo

    Ciao Carloooo ho compilato anche io il codice e sembra che vada...Ci sentiamo domenica ciauuuuu!!!!!
    Il timore di gravi danni non può da solo giustificare la soppressione della libertà di parola e di riunione.
    Louis Brandeis 1927

  9. #9
    Utente di HTML.it L'avatar di caralu
    Registrato dal
    Sep 2004
    Messaggi
    135
    Ho modificato il codice:
    siccome devo stampare le parole in ordine di occorrenza crescente
    (prima quelle che compaiono di meno, poi via via quelle più frequenti), ho introdotto l'algoritmo di ordinamento radix-sort che permette di ordinare la lista in ordine crescente, in modo da stampare la lista delle parole con l'ordine giusto.
    Nonostante questo ho un problema di compilazione e non riesco a trovare l'errore. L'algoritmo sembra corretto e non riesco a capire cosa abbia sbagliato. Se qualcuno può darmi una mano lo ringrazio davvero tantissimo.


    codice:
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <ctype.h>
    
    //Queste due costanti servono per l'ordinamento radix sort:
    #define RADICE_SIZE 10  //numero di cifre del sist. decimale
    #define MAX_CIFRE 3   //numero di cifre da 0 a 999
    
    
    //Mantiene le frequenze delle lettere
    int freqLettere['z' - 'a' + 1];  //Array di dimensione 26 (numero di lettere dell'alfabeto)
    
    //Mantiene le frequenze dei numeri
    int freqNumeri[10]; //Dimensione 10 per prendere in considerazione i numeri del sistema decimale
    
    //Mantiene il numero totale di caratteri trovati nel testo (lettere e numeri)
    int totaleCaratteri = 0;
    
    //Mantiene il numero totale di parole trovate nel testo
    int totaleParole = 0;
    
    
    
    //Definizione dell'elemento di una lista
    typedef struct list *lista;
    typedef struct list{
    	char *parola;
    	int frequenza[MAX_CIFRE];
    	list *next;
    }list;
    
    //Variabile che mantiene le lista di parole
    lista parole = NULL;
    
    //Inizializza a zero i vettori delle frequenze (lettere e numeri)
    void inizializza(){
            int i;
            for(i = 0; i < 10; i++)
                    freqNumeri[i] = 0;
            for(i = 0; i < ('z' - 'a' + 1); i++)
                    freqLettere[i] = 0;
                      }
    
    //Aggiorna le frequenze di lettere e numeri
    void aggiornaFrequenze(char *parola)
      {
            int i;
            char c;
            int len = strlen(parola); //Memorizza la dimensione di char della parola corrente
    
            for(i =  0; i < len; i++)
              {
                c = parola[i]; //Memorizza in c la parola corrente
                      //isalpha restituisce un valore diverso da zero se e è una lettera (maiuscola o minuscola)
                if(isalpha(c))
                  {
                    //la funzione tolower rende tutte le lettere minuscole
                    c = tolower(c);
    
                    //incrementiamo la posizione corrispondente di freqLettere
                    freqLettere[c - 'a']++;
                  }
    
      //isdigit controlla se il carattere corrente è un numero (in tal caso restituisce un valore diverso da 0)
                if(isdigit(c))
                  {
                  //incrementiamo la posizione corrispondente di freqLettere
                  freqNumeri[c - '0']++;
                  }
              }
            //Incremento il numero di parole totali
            totaleParole++;
            //Incremento il numero di caratteri totali
            totaleCaratteri = totaleCaratteri + len;
      }
    
    //Restituisce la prossima parola che si trova in testo a partire
    //dalla posizione posizioneCorrente. Una parola è definita come
    //una sequenza di lettere e/o numeri senza altri caratteri.
    //Restituisce NULL se non c'è una prossima parola
    
    char *prossimaParola(char *testo)
      {
      static int posizioneCorrente = 0;
      int i;
      int len = strlen(testo);  //len rappresenta il numero dei caratteri presenti nel testo
    
      //mi sposto avanti finche non trovo una lettera o un numero
        while(! isalnum(testo[posizioneCorrente]))
          {  //isalnum restituisce un valore diverso da zero se ciò che analizziamo è un carattere alfanumerico
          posizioneCorrente++;
          //se sono alla fine senza aver trovato lettere o numeri ritorno null
          if(posizioneCorrente >= len)
              return NULL;
          }
      //incremento i finchè trovo numeri e lettere; alla fine del cilco
      //i punta alla fine della parola corrente
      i = posizioneCorrente;  //in i si registra l'indice dell'array in cui inizia la prima frase del testo
        while(isalnum(testo[i]) && (i < len))
                i++; //i adesso assume il valore dell'indice dell'array che rappresenta la fine della parola
      int lunghezza = i - posizioneCorrente; //lunghezza è la lunghezza di caratteri della parola considerata
      char *parola = (char *)malloc((lunghezza + 1));
      for(i = 0; i <= lunghezza; i++)
              parola[i] = testo[posizioneCorrente + i];  //su parola viene memorizzata la parola corrente
      //Inserisco il carattere di fine stringa alla fine della parola
      parola[lunghezza] = '\0';
      posizioneCorrente = posizioneCorrente + i;  //riprende dalla fine della parola
      return parola;
    }
    
    void stampaNumeri(){
            printf("\n\n");
            int i;
            for(i = 0; i < 10; i++)
                    printf("\nfrequenza di %d: %d", i, freqNumeri[i]);
    }
    
    void stampaLettere(){
            printf("\n\n");
            int i;
            for(i = 0; i < ('z' - 'a' + 1); i++)
                    printf("\nfrequenza di %c: %d", 'a' + i, freqLettere[i]);
    }
    
    void stampaParole(){
            printf("\n\n");
            lista temp = parole;
            while(temp){
                    printf("\nfrequenza di %s: %d", temp->parola, temp->frequenza[0]);
                    temp = temp -> next;
            }
    }
    
    //Inserisce la parola nella lista parole, se non è gia presente,
    //altrimenti incrementa la sua frequenza
    void inserisciParola(char *parola){
            lista temp = parole;
            //Scorriamo la lista per vedere se la parola è ia stata inserita
            while(temp){
                    //Se la parola già c'è ci limitiamo a incrementare
                    //la frequenza
                    if(strcmp(temp -> parola, parola) == 0) //se strcmp restituisce 0 le stringhe sono uguali
                    {       temp->frequenza[2] = temp->frequenza[2]%RADICE_SIZE;
    temp->frequenza[1]=(temp->frequenza[1] % (RADICE_SIZE*RADICE_SIZE))/RADICE_SIZE;
    temp->frequenza[0]=(temp->frequenza[0] % (RADICE_SIZE*RADICE_SIZE*RADICE_SIZE))/(RADICE_SIZE*RADICE_SIZE);
                            return;
                    }
                    temp = temp -> next;
            }
            //Se la parola non è stata trovata, creiamo un nuovo elemento
            //che sarà inserito in testa alla lista.
            temp = (lista )malloc(sizeof(lista));
            temp -> parola = parola;
            temp -> frequenza[0] = 1;
            temp -> next = parole;
            //Facciamo puntare la lista 'parole' all'elemento di testa
            //appena isnerito
            parole = temp;
    }
    
    
    
    /*questa funzione crea dei "recipienti" per rappresentare il valore delle chiavi (sono 10 recipienti, da 0 a 9). Visto che un numero intero è costituito da più cifre ordinate dalla meno significativa, in ultima posizione, alla più significativa, in prima posizione (000, 001, 002,..., 010,...,100,..., 999) e
    ogni cifra K si trova nell'intervallo 0 <= k <= 9 ,in questo tipo di ordinamento la chiave di ordinamento viene scomposta in cifre utilizzando una radice RADICE_SIZE*/
     
    
    lista radice_sort(lista ptr)
    	{
     	lista davanti[RADICE_SIZE], dietro[RADICE_SIZE];
     	int i, j, cifra;
    
     	for(i=MAX_CIFRE-1;i>=0;i--)
     		{
      		for(j=0;j<RADICE_SIZE;j++)
          	davanti[j] = dietro[j] = NULL;  //i recipienti sono //implementati come code di dati: davanti[i] punta al primo //record nel recipiente i, mentre dietro[i] punta all'ultimo //record nel recipiente i.
    
      			while(ptr)
      				{
       			cifra = ptr->frequenza[i];
       			if(!davanti[cifra])
       				davanti[cifra] = ptr;
       			else
       				dietro[cifra]->next = ptr;
       			dietro[cifra] = ptr;
       			ptr = ptr->next;
      				}
      			ptr = NULL;
      			for(j=RADICE_SIZE-1;j>=0;j--)
      				{
      				if(davanti[j])
       				{
        				dietro[j]->next = ptr;
        				ptr = davanti[j];
       				}
      				}
          }
     	return ptr;
    	}
    
    int main(){
    	char * p;
    	char *testo = "ciao\tt\n1r&7 (re)re t zz";
    	while((p = prossimaParola(testo))){
    		aggiornaFrequenze(p);
    		inserisciParola(p);
    	}
    	stampaNumeri();
    	stampaLettere();
       parole = radice_sort(parole);
    	stampaParole();
    
    	printf("\n\nTotale parole: %d", totaleParole);
    	printf("\n\nTotale caratteri: %d", totaleCaratteri);
    
    	fflush(stdin);
       getchar();
    }

  10. #10
    Utente di HTML.it L'avatar di anx721
    Registrato dal
    Apr 2003
    Messaggi
    2,352
    Io nn ho errori di compilazione, ma errore a runtime; il problema è nella tua versione di iserisciParola.


    Sun Certified Java Programmer

    EUCIP Core Level Certified

    European Certification of Informatics Professionals

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.