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();
}