2017-09-03 6 views
1

해시 테이블을 구현하고 있지만 몇 가지 문제가 발생합니다. 단어가 추가 될 때 항상 업데이트 된 해시 테이블을 인쇄합니다. 문제는이 단어가 다시 나타날 때만 해당 빈도를 증가시켜야하지만 내 프로그램은 다음과 같습니다. 업데이트 된 빈도로 다시 인쇄 : 어떻게 한 번만 반복 된 단어를 인쇄 할 수 있습니까? 그리고 그들의 빈도를 보여주십시오.HashTable 반복 된 단어를 한 번만 인쇄하는 방법은 무엇입니까?

다른 문제는 print_freq 함수에 있습니다. 그것은 int freq를 받고이 주파수로 단어를 출력해야하지만 문제는 auxTable이 htable에서 단어를 저장하지 않는다는 것입니다. auxtable이 주파수를 정상적으로 저장하기 때문에 왜 작동하지 않는지 알 수 없습니다. 단어를 저장하려고하면 빈 문자 ""가 저장됩니다.

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <ctype.h> 

#define HTABLE_SIZE 1001 
#define MAX_LINE_SIZ 1024 

/* Hash Table */ 
typedef struct node* HASH_TABLE; /* estrutura de dados utilizadas para formar a hastable*/ 
struct node { 
    char *palavra; /*word*/ 
    int freq; 
}; 

/*Declaracao das funcoes*/ 
void inserirHashTable(char *s); 
void print_ht(); 
void print_test(); 

HASH_TABLE htable[HTABLE_SIZE] = { NULL }; /* Hash table que armazenará as palavras lidas do arquivos */ 
unsigned int chaves[HTABLE_SIZE]; /* Vetor que armazenará as chaves das palavras da tabela*/ 
int tamanhoChaves=-1; /*Variavel responsavel por contar a quantidade de chaves do vetor de chaves*/ 
int size = 0; /* variavel responsavel por armazenar o numero de elementos da tabela*/ 

/*Função responsavel por processar o arquivo, a mesma recebe o arquivo como parametro, 
* pega cada palavra presente no arquivo separa dos simbolos ?!+.-... e chama a função 
* inserirHT para inserir a palavra separada na tabela hash*/ 
void processarArquivo(FILE *fp) 
{ 
    const char *seperators = " ?!'\";,.:+-*&%(){}[]<>\\\t\n"; // caractertes que deveram ser separados 

    char line[MAX_LINE_SIZ]; 
    char *s; 
    while((fgets(line,MAX_LINE_SIZ, fp)) != NULL) //pegando a linha do arquivo 
    { 
     for (s=strtok(line,seperators); s; s=strtok(NULL,seperators)){ // separando a palavra 
      /*printf("Palavra a ser inserida %s \n",s); printf utilizado para mostrar 
      * a palavra que foi seperada e será inserida*/ 
      inserirHashTable(s);//Chamando a função inserir 
     } 
    } 
} 

/* Função responsavel por criar a chave de cada palavra que vai para tabela, 
    recebe como parametro um ponteiro para string, logo em seguida pega cada 
    caractere da string e gera um unsigned int para ele, retorna por fim o 
    modulo desse unsigned int pelo tamanho da tabela*/ 
unsigned int hash(char *tok) 
{ 
    unsigned int hv = 0; 
    while (*tok) 
     hv = (hv << 4) | toupper(*tok++); 
    /*printf("conversao: %d \n",hv); Printf utilizado para mostrar o valor de hv antes de ser retorna como modulo*/ 
    return hv % HTABLE_SIZE; 
} 

/* funcao responsavel por isenrir a palavra lida do arquivo na hash_table, 
* a funçãp recebe como parametro um ponteiro para estra palavra*/ 
void inserirHashTable(char *palavra) { 
    /*printf("Inserindo a palavra %s \n",palavra); Printf utilzado para mostrar a palavra a ser inserida na tabela*/ 
    tamanhoChaves++; /*Assim que uma palavra é inserida o numero de chaves é incrementado*/ 
    chaves[tamanhoChaves] = hash(palavra);/*A palavra é convertida na função hash e sua armazenada no vetor de chaves*/ 
    unsigned int hashval = chaves[tamanhoChaves]; /*Chave da apalvra*/ 

    if (htable[hashval]==NULL){ 
     /*printf("indice %u de %s \n",hashval,palavra);Printf utilizado para mostrar a chave e a palavra a ser inserida*/ 
     htable[hashval] = malloc(sizeof(palavra)); /*Alocando memoria para palavrra*/ 
     htable[hashval]->palavra = palavra ; /*Inserindo a palavra*/ 
     htable[hashval]->freq = 1; /*Incrementado sua frequencia*/ 
     size++; 

    }else { 
     /*If a words already exists in the table, i just incremente her frequency and the size. I guess the problem for repeated word is in here*/ 
     htable[hashval]->freq++; 
     size++; 
    } 
    /*A tabela é impressa a cada instante que uma palavra é inserida*/ 
    printf("\nAtualização da tabela\n"); 
    print_ht();/*Impressao das palavras já recebidas, a cada instante, com a quantidade de ocorrências*/ 

} 


/* Function responsible to print the words that were addedd to the hash table*/ 
void print_ht() { 
    int i=0; 
    /*Tabela auxiliar que servira para impressao das palavras e suas chaves*/ 
    HASH_TABLE *auxTable = (HASH_TABLE*) malloc(sizeof(HASH_TABLE)*size); 
    unsigned int hashval; /* variavel utilizada para pegar a chave das palavras no vetor de chaves */ 

    for(i; i < size; i++){ 
     hashval = chaves[i]; /*Pegando a chave*/ 
     /*printf("indice %u de %s \n",hashval,htable[hashval]->token);Printf utilizado para ver a chave e a palavra*/ 
     auxTable[i] = htable[hashval]; /*Atribuindo a palavra e a freq para tabela auxiliar*/ 
    } 

    /*qsort(auxTable,size,sizeof(link),compare);*/ 
    /*Imprimindo a tabela*/ 
    printf("Palavra | Frequencia\n"); 
    for (i=0; i < size; i++) 
     printf("%s \t  %d\n",auxTable[i]->palavra,auxTable[i]->freq); 
    free(auxTable); 
} 

/*Funcion responsible to print the words with the frequency received in the paramater*/ 
void print_freq(int freq){ 
    printf("Palavras com a frequencia: %d\n", freq); 
    int i, j =0; 
    HASH_TABLE *auxTable = (HASH_TABLE*) malloc(sizeof(HASH_TABLE)*size); 
    unsigned int hashval; 

    for(i; i < size; i++){ 
     hashval = chaves[i]; 
     /*printf("indice %u de %s \n",hashval,htable[hashval]->palavra);*/ 
     auxTable[i] = htable[hashval]; /*Problem is in here, when I do this, the auxTable[i]->palavra(word) = "", but the freq has been saved normally n*/ 
    } 

    printf("Palavra | Frequencia\n"); 
    for (i=0; i < size; i++) { 
     if(auxTable[i]->freq == freq) { 
      printf("%s \t   %d\n",auxTable[i]->palavra,auxTable[i]->freq); /*When I print, only the frequency is showed*/ 
     } 
    } 
    free(auxTable); 

} 
int main(int argc, char *argv[]) 
{ 
    int i; 
    FILE *fp; 

    fp = fopen("input.txt","r"); 
    if (NULL == fp) 
    { 
     fprintf(stderr,"Error ao abrir o arquivo: %s\n",fp); 
    } 
    printf("Imprimindo processo \n"); 
    processarArquivo(fp); /* debuuga aqui pra tu entender o q rola*/ 

    fclose(fp); 
    print_freq(3); //should print the word with freq equal to 3 
    //print_ht(); 
    /*clear_ht();*/ 
    return 0; 
} 

출력 :

https://imgur.com/a/PlRPp

+0

; 'chaves []'배열을 스캔합니다.이 배열은 발생시킨 각 단어의 해쉬 값을 당신이 만난 순서대로 포함하고 있습니다. 보조 테이블도 필요 없습니다. htable [hashval] -> palavra, htable [hashval], htable [hashval]! = NULL) printf ("% s \ t % d \ n" -> 주파수);'충분해야합니다. –

+2

아쉽게도 근본적인 버그가 있습니다. 두 단어가 같은 값으로 해시되면 동일한 단어로 취급합니다. 이를 * [hash collision] (https://en.wikipedia.org/wiki/Hash_table#Collision_resolution) *이라고하며이를 해결할 수있는 몇 가지 방법이 있습니다. 내가 가장 좋아하는 것은 노드를 단일 링크 목록으로 만드는 것이다. (그런데, 혼합 된 언어로 작성된 코드를 읽는 것은 매우 어렵습니다. 저는 영어 원어민이 아닙니다 .C 키워드는 이미 영어로되어 있으므로, 모든 코드와 주석이 영어로만.) –

+0

도움을 주신 분께 고마워,이 속어 이야기에 대해 유감스럽게 생각합니다. 그때는 모두 포르투갈어로되어 있습니다. ', btw, 내 문제는 thats, 나는 해시 콜리 전 (hash colisions) 이 자료 나 코드가 있습니까? –

답변

0

문제는 당신이 node.palavra로 저장하는 것입니다. 추적 할 경우 inserirHashTable의 입력이며 이는 strtokprocessarArquivo에 호출 한 결과입니다. 이 포인터는 포인터가 로컬 변수 lineprocessarArquivo 인 입력 배열 내에 있기 때문에 털이 많습니다. 파일에서 다른 행을 스캔하거나이 기능을 종료하면이 옵션은 유효하지 않게됩니다. 이것은 해시 테이블 (processarArquivoline이 아직 범위에 있음)을 생성하는 동안 정확하게 작동하는 이유이며, 일단 함수가 종료되면 (즉, main으로 돌아가서 print_freq으로 전화를하면) 정의되지 않은 동작을합니다. 당신이 malloc를 호출하는 방법을

  • 주의 사항 :

    지금, inserirHashTable 개선하기 위해 2 개 포인트가 있습니다. 새로운 HASH_TABLE 구조체를 저장하기 위해 sizeof (char *) 바이트를 할당합니다. 왜?

  • 무엇보다 포인터를 palavra 필드로 복사하고 있습니다. make a copy here을 입력해야합니다.

보너스 문제 print_freq에서 i 변수 auxTable의 존재 및 해시 값이 잘못되는 고유 가정 사실 초기화되지 않은 있습니다 (어떻게 될 수 있을까? 이상 1,001 별개의 단어가있다!).

+0

오, 젠장, 내 모든 문제는 processarArquivo에 있습니까? 내가 파일을 읽고 그 단어들을 inserirHastTable에 보낼 수있는 방법을 알고 있니? ' –

+0

@RafaelCamara 나는 문자열의 복사본을 만드는 방법을 제안했다. 당신이 파일을 읽는 방법은 나에게 잘 보입니다. – orhtej2

1

다음은 충돌을 해결하는 방법이며 필요한 경우 모든 단어를 다시 치우지 않고 해시 테이블의 크기를 조정할 수 있습니다.

먼저, 단일 연결 목록을 사용하여 동일한 해시를 가진 모든 다른 단어를 포함합니다. 또한 해시 테이블의 크기를 쉽게 조정할 수 있도록 해시 - 전체 해시 (모듈 해시 테이블 크기가 아닌)를 저장합니다.

struct hash_entry { 
    struct hash_entry *next; /* Pointer to next word in this hash table entry */ 
    size_t    hash; /* Any unsigned type works; I just like size_t */ 
    size_t    freq; /* Frequency */ 
    char    word[]; /* C99 flexible array member */ 
}; 

해시 테이블 size 포인터 단지 어레이가 단독 링크드리스트에있는 hash에 해시 각 단어이며, 마지막으로, I 단어 자체에 대한 C99 가요 어레이 부재을 사용하고자 entry[hash % size]에 걸려 :

struct hash_table { 
    size_t    size; 
    struct hash_entry **entry; 
}; 

기본 기능을 해시 테이블을 초기화 크기를 조정하고 확보하는 것은 다음

int hash_table_create(struct hash_table *ht, size_t size) 
{ 
    size_t i; 

    if (ht == NULL || size < 1) 
     return -1; /* Invalid parameters */ 

    ht->size = size; 
    ht->entry = malloc(size * sizeof ht->entry[0]); 
    if (ht->entry == NULL) 
     return -2; /* Cannot allocate memory */ 

    /* Clear all entries: no hashes/chains yet! */ 
    for (i = 0; i < size; i++)   
     ht->entry[i] = NULL; 

    return 0; /* Success, no errors. */ 
} 

void hash_entry_free(struct hash_entry *entry) 
{ 
    while (entry) { 
     struct hash_entry *next = entry->next; 

     /* I like to "poison" the freed entries; 
      this makes debugging easier, if you try 
      to access an already freed entry. */ 
     entry->hash = 0; 
     entry->freq = 0; 
     entry->next = NULL; 

     free(entry); 

     entry = next; 
    } 
} 

void hash_table_free(struct hash_table *ht) 
{ 
    if (ht != NULL) { 
     size_t i; 

     for (i = 0; i < ht->size; i++) 
      if (ht->entry[i] != NULL) 
       hash_entry_free(ht->entry[i]); 

     free(ht->entry); 

     ht->size = 0; 
     ht->entry = NULL; 
    } 
} 

int hash_table_resize(struct hash_table *ht, size_t new_size) 
{ 
    struct hash_entry **entry; 
    struct hash_entry *curr, *next; 
    size_t i, k; 

    if (!ht || new_size < 1) 
     return -1; /* Invalid parameters */ 

    if (ht->size < 1 || !ht->entry) 
     return -2; /* Hash table is already freed */ 

    entry = malloc(new_size * sizeof entry[0]); 
    if (!entry) 
     return -3; /* Not enough memory */ 

    for (i = 0; i < new_size; i++) 
     entry[i] = NULL; 

    for (i = 0; i < ht->size; i++) { 

     /* Chain in the old hash table entry */ 
     curr = ht->entry[i];    

     /* We are paranoid, and clear the old entry. */ 
     ht->entry[i] = NULL; 

     while (curr) { 
      /* Remember next hash in this chain */ 
      next = curr->next; 

      /* Index to the new hash table */ 
      k = curr->hash % new_size; 

      /* Prepend in front of the new hash table entry chain */ 
      curr->next = entry[k]; 
      entry[k] = curr; 

      /* Advance to the next entry in the old chain */ 
      curr = next; 
     } 

    /* The old table is now useless. Free it, and use the new one. */ 
    free(ht->entry); 
    ht->entry = entry; 
    ht->size = new_size; 

    return 0; /* Success; no errors. */ 
} 
012입니다 기능을 해시로 3,516,

, 나는 djb2 xor hash 좋아한다 : 나는 또한이 개 기능으로 해시 테이블에 문자열/단어를 추가 분할 것

size_t hash(const char *s) 
{ 
    if (s != NULL) { 
     size_t result = 5381; 

     while (*s != '\0') 
      result = (result * 33)^(*(s++)); 

     return result; 
    } else 
     return 0; 
} 

size_t hash_len(const char *s, const size_t len) 
{ 
    if (s != NULL) { 
     const char *z = s + len; 
     size_t result = 5381; 

     while (s < z) 
      result = (result * 33)^(*(s++)); 

     return result; 
    } else 
     return 0; 
} 

가 : 첫 번째 함수는로 struct hash_entry 복사 소스 단어를 생성 및 두 번째 함수는 항목을 생성하는 제를 사용하고, 그런 다음 해시 테이블에 추가한다 :

struct hash_entry *hash_entry_new_len(const char *src, size_t len) 
{ 
    struct hash_entry *h; 

    if (len > 0 && !src) 
     return NULL; /* NULL src, but positive len! */ 

    /* To accommodate the flexible array member, we need 
     to add its size to the structure size. Since it 
     is a string, we need to include room for the '\0'. */ 
    h = malloc(sizeof (struct hash_entry) + len + 1); 
    if (!h) 
     return NULL; /* Out of memory */ 

    /* Copy the string to the entry, */ 
    if (len > 0) 
     memcpy(h->word, src, len); 

    /* Add the string-terminating nul char, */ 
    h->word[len] = '\0'; 

    /* clear the next pointer, */ 
    h->next = NULL; 

    /* set the frequency count to 1, */ 
    h->freq = 1; 

    /* and compute the hash. */ 
    h->hash = hash_len(src, len); 

    /* Done! */ 
    return h; 
} 

struct hash_entry *hash_entry_new(const char *src) 
{ 
    const size_t len = (src) ? strlen(src) : 0; 
    return hash_entry_new_len(src, len); 
} 

struct hash_entry *hash_table_add_part(struct hash_table *ht, const char *src, const size_t len) 
{ 
    struct hash_entry *h; 
    size_t    k; 

    if (!ht || ht->size < 1) 
     return NULL; /* No hash table! */ 

    /* We'll check src and len, so we report the right error. */ 
    if (!src && len > 0) 
     return NULL; /* Invalid src (NULL)! */ 

    h = hash_entry_new(src, len); 
    if (!h) 
     return NULL; /* Must be out of memory! */ 

    /* Index into the hash table */ 
    k = h->hash % ht->size; 

    /* Prepend new hash table entry to the beginning of the chain. */ 
    h->next = ht->entry[k]; 
    ht->entry[k] = h; 

    /* Success! */ 
    return h; 
} 

/* Helper function, so you don't need to specify the length 
    if you wish to add a copy of entire source string. */ 
struct hash_entry *hash_table_add(struct hash_table *ht, const char *src) 
{ 
    const size_t len = (src) ? strlen(src) : 0; 
    return hash_table_add_part(ht, src, len); 
} 

len = (src) ? strlen(src) : 0 식은 if (src != NULL) len = strlen(src); else len = 0; 속기이다. 문자열 길이를 검사하는 안전한 방법으로 많이 사용하거나 문자열이 비어 있거나 NULL이면 0을 사용합니다.

NULL 문자열은 해시 0을 수신하지만 빈 문자열은 5381으로 해시됩니다. 그것은 중요하지 않습니다, 나는 그저 그런 식으로 (또는 완전히 그리고 과도하게 질기가 고 뜨거운 공기로 가득 차 있습니다.) 말하고 싶습니다.

내 "정상적인"기능은 _len()으로 끝나고 같은 이름의 기능이 있지만 _len() 접미사가없는 기능은 전체 문자열을 사용하는 도우미 기능입니다. strtok()을 사용하여 문자열을 분할하지 않아도 유용합니다. strspn()/strcspn() 또는 심지어 정규식을 사용하여 각 문자열에서 흥미로운 단어를 찾습니다.

해시 테이블에서 특정 단어를 찾으려면 비교할 원래 문자열이 있어야합니다. 해시 자체는 충분하지 않습니다 :

int hash_table_seen_len(struct hash_table *ht, const char *src, const size_t len) 
{ 
    struct hash_entry *h; 

    /* Sanity checks first. */ 
    if (!ht || (!src && len > 0)) 
     return -1; /* Invalid parameters! */ 

    h = hash_table_find_len(ht, src, len); 
    if (h) { 
     /* Found match; increment freq counter. */ 
     h->freq++; 
     /* All done. */ 
     return 0; 
    } 

    /* Not found. Add to hash table. */ 
    h = hash_table_add_len(ht, src, len); 
    if (!h) { 
     /* An error occurred; should be "out of memory", 
      since we checked the other causes earlier 
      in this function. */ 
     return -1; 
    } 

    /* The word was added to the hash table. 
     Since its freq count is 1, we do not need 
     to increment it; we're done. */ 
    return 0; 
} 

int hash_table_seen(struct hash_table *ht, const char *src) 
{ 
    const size_t len = (src) ? strlen(src) : 0; 
    return hash_table_seen_len(ht, src, len); 
} 

내가, 내가 좋겠 주파수의 순서로 해시 테이블 항목을 인쇄 할 것을 확신 : 단어의 빈도를 계산

struct hash_entry *hash_table_find_len(struct hash_table *ht, const char *src, const size_t len) 
{ 
    const size_t hashval = hash_len(src, len); 
    struct hash_entry *curr = ht->entry[hashval % ht->size]; 

    /* No matches for sure? */ 
    if (!curr) 
     return NULL; 

    /* We have a chain (singly-linked list). 
     Check each one in turn. */ 
    while (curr) { 

     /* Since we kept the entire hash value, 
      and not just the index to the hash table, 
      we can use the extra bits to exclude 
      words that have the same hash modulus (index) 
      but different complete hash value! */ 
     if (curr->hash == hash) { 

      /* We cannot use strncmp() if len == 0, 
       so we check that case separately. */ 
      if (len == 0) { 
       if (curr->word[0] == '\0') 
        return curr; /* Match found! */ 
      } else { 
       if (!strncmp(curr->word, src, len) && 
        curr->word[len] == '\0') 
        return curr; /* Match found! */ 
      } 
     } 

     /* No match. Check next one in chain. */ 
     curr = curr->next; 
    } 

    /* Nope, no match. */ 
    return NULL; 
} 

struct hash_entry *hash_table_find(struct hash_table *ht, const char *src) 
{ 
    const size_t len = (src) ? strlen(src) : 0; 
    return hash_table_find_len(ht, src, len); 
} 

지금은 간단합니다 가장 큰 주파수를 찾기 위해 일을하고, 다른 하나는 주어진 주파수보다 큰 주파수 덜 찾는 방법은 다음과 같습니다 : 두 도우미 함수를 사용하여 마지막으로

size_t hash_table_max_freq(struct hash_table *ht) 
{ 
    size_t result = 0; 
    size_t i; 

    if (!ht || ht->size < 1) 
     return 0; /* No hash table. */ 

    for (i = 0; i < ht->size; i++) { 
     struct hash_entry *curr = ht->entry[i]; 

     while (curr) { 
      if (curr->freq > result) 
       result = curr->freq; 
      curr = curr->next; 
     } 
    } 

    return result; 
} 

size_t hash_table_next_freq(struct hash_table *ht, const size_t max_freq) 
{ 
    size_t result = 0; 
    size_t i; 

    if (!ht || ht->size < 1) 
     return 0; /* No hash table. */ 

    for (i = 0; i < ht->size; i++) { 
     struct hash_entry *curr = ht->entry[i]; 

     while (curr) { 
      if (curr->freq > result && curr->freq < max_freq) 
       result = curr->freq; 
      curr = curr->next; 
     } 
    } 

    return result; 
} 

, 우리는의 인터페이스를 "훔칠"수

int hash_table_for_all(struct hash_table *ht, 
         int (*func)(struct hash_entry *, void *), 
         void *user_data) 
{ 
    int  retval; 
    size_t i; 

    if (!ht || !func) 
     return -1; /* NULL hash table or function. */ 

    for (i = 0; i < ht->size; i++) { 
     struct hash_entry *curr = ht->entry[i]; 
     while (curr) { 
      retval = func(curr, user_data); 
      if (retval) 
       return retval; 
      curr = curr->next; 
     } 
    } 

    return 0; 
} 

int hash_table_for_freq(struct hash_table *ht, const size_t freq, 
         int (*func)(struct hash_entry *, void *), 
         void *user_data) 
{ 
    int  retval; 
    size_t i; 

    if (!ht || !func) 
     return -1; /* NULL hash table or function. */ 

    for (i = 0; i < ht->size; i++) { 
     struct hash_entry *curr = ht->entry[i]; 
     while (curr) { 
      if (curr->freq == freq) { 
       retval = func(curr, user_data); 
       if (retval) 
        return retval; 
      } 
      curr = curr->next; 
     } 
    } 

    return 0; 
} 

위의 코드 중에 심지어 컴파일 - 테스트, 당신은 오타를 발견 (또는 컴파일 시간 오류로 실행), 그래서 만약주지하시기 바랍니다됩니다 :는 특정 주파수 모든 단어, 또는 모든 단어를 찾을 수 내가 확인할 수 있도록 의견에서 알 수 있습니다.

0

나는 너의 운동을했다.

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

//hash table size 
#define SIZE 1000 
//maximum size of the input string 
#define STR_LEN 100 

typedef struct linked_list { 
    unsigned char value[STR_LEN]; 
    unsigned int cnt; 
    struct linked_list *next; 
} linked_list; 

void print_items(int freq); 
void print_freq(int freq); 
void print_table(); 
int add_to_table(unsigned char *str); 
unsigned long get_hash(unsigned char *str); 

linked_list* table[SIZE]; 

int main() { 
    unsigned char str[STR_LEN]; 
    //the fgets function allows the spaces in the string. 
    //so, strings like: 'red green blue' are possible. 
    while(fgets(str, STR_LEN, stdin)) { 
     sscanf(str, "%[^\n]", str); 

     add_to_table(str); 
    } 

    print_freq(2); 

    return 0; 
} 

void print_table(){ 
    puts("Whole table"); 
    print_items(0); 
} 

void print_freq(int freq){ 
    printf("Words with frequency: %d\n", freq); 
    print_items(freq); 
} 

// if freq = 0, it prints all hash table items. 
// if freq = 1, 2, 3... it prints only items with the specific frequency. 
void print_items(int freq) { 
    int i; 
    linked_list *node; 
    puts("----------------------"); 
    puts("Values\t| Frequency"); 
    for(i = 0; i < SIZE; i++) { 
     node = table[i]; 
     while(node) { 
      if(freq && freq != node->cnt) { 
       node = node->next; 
       continue; 
      } 
      printf("%s\t| %d\n", node->value, node->cnt); 
      node = node->next; 
     } 
    } 
    puts("----------------------"); 
} 

//Collision processing implemented by the linked list. 
//In the beginning, all items of the hash table are NULL. 
// 
//The first string with specific hash goes to the corresponding 'table' array index 
//in the linked list's node form. 
// 
//Then, if the collision occurs (different string with the same hash) 
//the new node shifts the previous node and linking to it 
int add_to_table(unsigned char *str) { 
     unsigned long hash; 
     hash = get_hash(str); 
     hash = hash & SIZE; 

     linked_list *node = table[hash]; 

     while(node) { 
      if(strcmp(str, node->value) == 0) { 
       node->cnt++;  
       return 1; 
      } 
      node = node->next; 
     } 

     //if the item does not exist (wasn't found in the previous while loop), 
     //the new node is created 
     linked_list *new_node = malloc(sizeof(linked_list)); 
     //the new node 'next' field is pointing to the previous 
     //first node (head) of the linked list 
     new_node->next = table[hash]; 
     new_node->cnt = 1; 
     strcpy(new_node->value, str); 

     //and the new node became the new 'head' 
     table[hash] = new_node; 

     print_table(); 

     return 1; 
} 

// the 'djb2' hash algorithm is used 
unsigned long get_hash(unsigned char *str) 
{ 
    unsigned long hash = 5381; 
    int c; 

    while (c = *str) { 
     hash = hash * 33 + c; 
     str++; 
    } 

    return hash; 
} 

테스트 : 당신은 실제로 해시 테이블을 스캔하지 않는

one       <--- input "one" 
Whole table     <--- output 
----------------------   the whole table is printed each time, 
Values | Frequency    the new string is added 
one  | 1 
---------------------- 
two       <--- input "two" 
Whole table 
---------------------- 
Values | Frequency 
two  | 1 
one  | 1 
---------------------- 
one       <--- input - no output, because the hash table 
            already have this string 
two       <--- input - the same 
three      <--- input - the output is appearing now, 
            'three' didn't inputted before 
Whole table 
---------------------- 
Values | Frequency 
two  | 2 
three | 1 
one  | 2 
---------------------- 
Words with frequency: 2  <--- I am send EOF (end of file) to the 
            program by Ctrl-D 
---------------------- 
Values | Frequency   
two  | 2 
one  | 2 
----------------------