Подсчитать количество слов в файле - C (СИ) (71340)

Узнай цену своей работы

Формулировка задачи:

Задачка вот такая, нужна помощь с ее решением)

Один из способов идентификации автора литературного произведения – подсчет частоты вхождения отдельных слов. В заданном текстовом файле найти 20 наиболее часто встречающихся слов с указанием частоты использования каждого из них.

Решение задачи: «Подсчитать количество слов в файле»

textual
Листинг программы
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <ctype.h>
#include <locale.h>
#define MAX_SIZE   256
typedef unsigned char uchar;
 
typedef struct _word {
    struct _word* next;
    const  uchar* ptr;
    unsigned      cnt;
} sword;
 
typedef struct {
    sword* arr[MAX_SIZE];
    int    cnt;
} htab;
 
static unsigned __calc_hash(const uchar* s);
static int __scmp(const uchar* s1, const uchar* s2);
static char* readfile(const char* fn);
static void  sword_fill(htab* ht, uchar* s);
 
static void   htab_init(htab* ht);
static int    htab_add(htab* ht, const uchar* w);
static void   htab_clear(htab* ht);
static sword* htab_min(htab* ht);
static void   htab_print(FILE* _out, htab* ht, int num);
 
int main(void){
    htab  ht;
    char* buf = readfile("file.txt");
    if(buf == NULL)
        return 1;
 
    setlocale(LC_CTYPE, "Russian_Russia.1251");
    sword_fill(&ht, (uchar*)buf);
    htab_print(stdout, &ht, 20);
 
    htab_clear(&ht);
    free(buf);
    return 0;
}
 
//инициализация
static void htab_init(htab* ht){
    int i;
    for(i = 0; i < MAX_SIZE; ++i)
        ht->arr[i] = NULL;
    ht->cnt = 0;
}
 
//добавление
static int htab_add(htab* ht, const uchar* w){
    sword*   p;
    unsigned key = __calc_hash(w);
 
    for(p = ht->arr[key]; p != NULL; p = p->next){
        if(__scmp(p->ptr, w)){
            ++(p->cnt);
            return 0;
        }
    }
 
    p = (sword*)malloc(sizeof(sword));
    if(p != NULL){
        p->cnt  = 1;
        p->ptr  = w;
        p->next = ht->arr[key];
        ht->arr[key] = p;
        ++(ht->cnt);
    }
    return (p != NULL);
}
 
//минимум
static sword* htab_min(htab* ht){
    int    i;
    sword* p;
    for(i = 0; i < MAX_SIZE; ++i){
        if((ht->arr[i] != NULL) && (ht->arr[i]->cnt > 0))
            break;
    }
    if(i == MAX_SIZE)
        return NULL;
 
    p = ht->arr[i];
    for(; i < MAX_SIZE; ++i){
        if((ht->arr[i] != NULL) && (ht->arr[i]->cnt > p->cnt))
            p = ht->arr[i];
    }
    return p;
}
 
//вывод результата 
static void htab_print(FILE* _out, htab* ht, int num){
    int    i;
    sword* p;
    if(ht->cnt < num)
        num = ht->cnt;
 
    for(i = 0; i < num; ++i){
        if((p = htab_min(ht)) != NULL){
            fprintf(_out, "%s(%d)\n", p->ptr, p->cnt);
            p->cnt = 0;
        }
    }
    fflush(_out);
}
 
//удаление всех
static void htab_clear(htab* ht){
    int    i;
    sword* t;
    for(i = 0; i < MAX_SIZE; ++i){
        while(ht->arr[i] != NULL){
            t = ht->arr[i];
            ht->arr[i] = ht->arr[i]->next;
            free(t);
        }
    }
    ht->cnt = 0;
}
 
//...
 
static void sword_fill(htab* ht, uchar* s){ 
    uchar* p;
    htab_init(ht);
 
    while(*s){
        while(*s && !isalnum(*s))
            ++s;
        
        for(p = s; isalnum(*p); ++p)
            ;
        if(s != p){
            if(*p)
                *p++ = '\0';
            htab_add(ht, s);
        }
        s = p;
    }
}
 
static unsigned __calc_hash(const uchar* s){
    unsigned n = 0;
    while(*s)
        n += (unsigned)toupper(*s++);
    return n % MAX_SIZE;
}
 
static int __scmp(const uchar* s1, const uchar* s2){
    while(*s1 && (toupper(*s1) == toupper(*s2))){
        ++s1;
        ++s2;
    }
    return (!*s1 && !*s2);
}
 
static char* readfile(const char* fn){
    char*  s;
    long   n;
    size_t i;
    FILE*  fp = fopen(fn, "rb");
    if(fp == NULL)
        return NULL;
 
    fseek(fp, 0L, SEEK_END);
    n = ftell(fp);
    if(n <= 1L){
        fclose(fp);
        return NULL;
    }
    
    s = (char*)malloc((n + 1) * sizeof(char));
    if(s == NULL){
        fclose(fp);
        return NULL;
    }
    fseek(fp, 0L, SEEK_SET);
    i = fread(s, sizeof(char), (size_t)n, fp);
    fclose(fp);
    
    if(i == (size_t)n)
        s[i] = '\0';
    else {
        free(s);
        s = NULL;
    }
    return s;
}

Объяснение кода листинга программы

  1. В данной программе используется язык программирования C.
  2. Программа подсчитывает количество слов в файле.
  3. Для решения задачи используется хэш-таблица (htab).
  4. Хэш-таблица содержит структуру данных sword, которая включает указатель на следующую структуру, указатель на строку и счетчик количества упоминаний слова.
  5. Программа считывает файл построчно и разбивает каждую строку на отдельные слова.
  6. Каждое слово проверяется на наличие в хэш-таблице. Если слово уже присутствует в хэш-таблице, увеличивается его счетчик. Если слова нет в хэш-таблице, оно добавляется в хэш-таблицу.
  7. В конце программы выводятся наиболее часто встречающиеся слова в порядке убывания их частоты.
  8. Для определения хэш-функции используется функция __calc_hash, которая преобразует слово в верхний регистр, суммирует значения символов и берет остаток от деления на размер массива MAX_SIZE.
  9. Для сравнения двух строк используется функция __scmp, которая сравнивает символы строк до тех пор, пока не найдет различие или не достигнет конца одной из строк.
  10. Для чтения файла используется функция readfile, которая открывает файл, считывает его содержимое в буфер и возвращает указатель на буфер. Если файл не может быть прочитан, функция возвращает NULL.

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

10   голосов , оценка 4.1 из 5
Похожие ответы