将单词存储到哈希表中

时间:2016-12-27 06:07:54

标签: data-structures linked-list hashtable valgrind

我有一个文件,其中包含txt文件中的英文单词,每个单词都在一个新行中。 我是C的初学者。我使用loadunload函数将所有单词存储到哈希表中(单独链接)并从内存中卸载它们但是遇到了一些问题。

函数(main.c中的代码是正确的):

  

负载:

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

#include "dictionary.h"

#define SIZE 26

typedef  struct node
{
    char word[LENGTH+1];
    struct node *next;
}node;

unsigned int hash_num = 0;
node *hashtable[SIZE];  //26 letters in alphabet

node *head = NULL;

// hashfunction
unsigned int hash(char const *key)  
{
    unsigned int hash= tolower(key[0]) - 'a';
    return hash % SIZE;
}

/**
 * Loads dictionary into memory.  Returns true if successful else false.
 */
bool load(const char* dictionary)
{

    unsigned int hash_index=0;

    FILE *fp = fopen(dictionary, "r");
    if(fp == NULL)
    {
        fprintf(stderr, "Couldn't open %s",dictionary);
        return false;
    }

    //dictionary 


    while(!feof(fp))
    {
        node *temp = malloc(sizeof(node));
        if (temp == NULL)
        {
            unload();
            fclose(fp);
            return false;
        }


        if(fscanf(fp , "%s", temp->word) == 1)   //storing word of dictionary in my new_node -> word
        {
            hash_index = hash(temp->word); 
            head= hashtable[hash_index];    //head always points to first element of linked list (containting word of dictionary)


            temp->next = head;  
            head = temp;        


            hash_num++;
        }
        else    //if fscanf couldn't store the word (return 0)
        {
            free(temp);    //free last temp
            break;
        }
    }

    fclose(fp);
    return true;

}
  

卸载:

bool unload(void)
{

    for(int i=0; i<SIZE; i++)
    {
        if(hashtable[i] != NULL)      //if hashtable isn't NULL (has nodes)
        {
            node *cursor = hashtable[i];        //cursor points at head of individual linked list
            while(cursor != NULL)       //free them
            {
                node *temp = cursor;
                cursor = cursor->next;
                free(temp);
            }
        }
    }

    return true;
}

有谁能告诉我逻辑是否正确?每当我运行valgrind时,它告诉我所有节点都已分配,但只有3个空闲&#39; d。

total heap usage: 143,094 allocs, 3 frees, 8,014,288 bytes allocated
LEAK SUMMARY:
==15903==    definitely lost: 8,013,040 bytes in 143,090 blocks
==15903==    indirectly lost: 0 bytes in 0 blocks
==15903==      possibly lost: 0 bytes in 0 blocks

1 个答案:

答案 0 :(得分:1)

检查提供的源代码(缺少&#34; dictionary.h&#34;)时,主要问题是位于load()函数中。

问题1(主要) - 添加新词/节点时hashtable[]永远不会更新(在计算hash_index = hash(temp->word);之后)。

  

要存储更新的链表(管理为反向),它是   必须使用新节点更新hashtable[hash_index]   指针(已分配的temp节点)。

temp->next = head;
head = temp;

hashtable[hash_index] = head; // update the hashtable[] pointer

hash_num++;
  

没有全局变量head的替代解决方案。

temp->next = hashtable[hash_index]; //head always points to first element...
hashtable[hash_index] = temp; // update the hashtable[] pointer

hash_num++;

而不是

temp->next = head;
head = temp;

hash_num++;

问题2(小) - hashtable[SIZE]从未初始化。

  

unload()函数中,在for循环中,if条件   if(hashtable[i] != NULL)假定数组的每个项目都是   初始化为NULL。

在开头添加load()函数或在调用它之前,使用for循环初始化每个指针。

for(int i=0; i<SIZE; i++)
{
    hashtable[i] = NULL;
}

问题3(潜在错误来源) - 正如评论者所建议的,使用head,声明为全局变量node *head = NULL;可能是错误的潜在来源。

  

load()函数中,变量head用作临时变量   存储但可以在软件运行期间存储价值。如果是读操作   结果是在没有熟知的写操作之前执行的   即使编译没有检测到,也可能是意外错误   错误或警告。

     

最好的方法是减少全局变量的数量   可能的。

增强功能(反向链接列表) - 因为托管链接列表正在前面添加新项目,所以这是最终添加新项目的解决方案。

node *first = hashtable[hash_index];
if (first == NULL) {
    hashtable[hash_index] = temp;
}
else {
    temp->next = NULL; // ending the list
    while (first->next!=NULL) {
        first = first->next;  // loop until last node
    }
    first->next = temp; // linking to the last node
}

hash_num++;

而不是

head= hashtable[hash_index];    //head always points to first element ...

temp->next = head;  
head = temp;        

hash_num++;