【问题标题】:Hash Table in C (find the frequency of every word)C中的哈希表(查找每个单词的频率)
【发布时间】:2014-12-23 13:34:10
【问题描述】:

我想为我必须在我的大学发送的练习创建一个哈希表。 该程序将打开多个文件,将每个文件的内容分解为<<words>>(令牌),并将每个<<word>> 以每个<<word>> 的频率保存在一个哈希表中。

如果单词已经在哈希表中,程序会增加单词的频率。

最后,程序将相应地打印单词及其频率。 此外,频率应从最高词频到最低词频打印。 <<words>> 的比较将忽略大小写字母。

例如,如果文件包含:one two three four Two Three Four THREE FOUR FoUr 它应该打印:

四个4
三 3
两个 2
一个 1

教授给了我们一个我们应该完成的模板,但我真的很困惑如何处理 insert_ht()clear_ht() 函数以及比较函数。

代码如下:

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

#define HTABLE_SIZ 1001
#define MAX_LINE_SIZ 1024

/* Hash Table */
typedef struct node* link;
struct node { char *token; int freq; link next; };

link htable[HTABLE_SIZ] = { NULL }; /* Table of lists (#buckets) */
int size = 0; /* Size (number of elements) of hash table */

unsigned int hash (char *tok );
void insert_ht (char *data);
void clear_ht ( );
void print_ht ( );

void Process(FILE *fp);


int main(int argc, char *argv[])
{
    int i;
    FILE *fp;
    for (i=1; i < argc; i++)
    {
        fp = fopen(argv[i],"r");
        if (NULL == fp)
        {
            fprintf(stderr,"Problem opening file: %s\n",argv[i]);
            continue;
        }
    Process(fp);
    fclose(fp);
    }
    print_ht();
    clear_ht();
    return 0;
}


void Process(FILE *fp)
{
    const char *seperators = " ?!'\";,.:+-*&%(){}[]<>\\\t\n";

    char line[MAX_LINE_SIZ];
    char *s;
    while((fgets(line,MAX_LINE_SIZ, fp)) != NULL)
    {
        for (s=strtok(line,seperators); s; s=strtok(NULL,seperators))
            insert_ht(s);
        }
    }

/* Hash Function */
unsigned int hash(char *tok)
{
    unsigned int hv = 0;
    while (*tok)
        hv = (hv << 4) | toupper(*tok++);
    return hv % HTABLE_SIZ;
}


void insert_ht(char *token)
{
……………………………………………
}
void clear_ht()
{
……………………………………………
}
int compare(const void *elem1, const void *elem2)
{
……………………………………………
}
void print_ht()
{
    int i, j=0;
    link l, *vector = (link*) malloc(sizeof(link)*size);
    for (i=0; i < HTABLE_SIZ; i++)
        for (l=htable[i]; l; l=l->next)
            vector[j++] = l;
        qsort(vector,size,sizeof(link),compare);
        for (i=0; i < size; i++)
            printf("%-50s\t%7d\n",vector[i]->token,vector[i]->freq);
        free(vector);
}

【问题讨论】:

  • 标准警告:请do not castmalloc()的返回值。
  • 还没到编译步骤。试图找出程序中的主要功能。不过感谢您的提示:)

标签: c hashtable frequency words


【解决方案1】:

我会在新帖子中回复你,因为在 cmets 中很难做到详尽。

1。马洛克

那我为什么需要使用 malloc 呢?我不应该直接写到htable吗? (在 insert_ht() 函数上)

您需要使用 ma​​lloc,因为您在 struct (char *token) 中声明了一个 char 指针。问题是你永远不会初始化指向任何东西的指针,而且你不知道令牌的大小,你需要 malloc 每个令牌。

但是,当您使用 strdup(token) 时,您不需要 malloc 令牌,因为 strdup 需要。所以不要忘记释放每个令牌以避免内存泄漏。

2。段错误

我无法测试您的代码,但似乎以下行导致了分段错误:

list = htable[hashval]->token 

确实,您尝试在 htable[hashval] 为 NULL 时访问 token,并将 char * 分配给 link 类型(列表)。

你需要用这个循环:

for(list = htable[hashval]; list != NULL; list = list->next) { ... }

3。备注

  • if (x=1) 应该是 if(x==1)
  • 如果不需要,不要 malloc new_list
  • 因为如果在 htable[hashval] 为 NULL 时使用 new_list,new_list-&gt;next = htable[hashval]; 会将 new_list->next 设置为 NULL。
  • 您应该使用 gcc 中的 -Wall 选项(用于警告),并且您可以使用 valgrind 来了解您的分段错误。在这种情况下,请使用带有调试模式 (-g) 的 gcc。

【讨论】:

  • 谢谢。我认为主要问题在于主程序中的 fopen 。我不知道为什么会出现分段错误。我运行它就像./program_name ~/workspace/file
  • 没关系。错误仍然存​​在于insert_ht() 中。我改变了你所说的,但仍然出现 seg.fault。
  • @Scotoner 直到今天,我都无法运行您的程序。今天下午我会试试看,我们会发现当前的问题是什么。
【解决方案2】:

双重和最终编辑:我找到了解决方案。显然出于某种原因,我的 compare 函数是错误的。 我还没有弄清楚为什么,但这是正确的,希望其他人会发现这篇文章有帮助!

int compare(const void *elem1, const void *elem2)
{
    
     return (*(link*)elem2)->freq - (*(link*)elem1)->freq;
}

编辑:删除旧答案。找到了我认为的正确方法,但我现在有另一个问题。 compare 函数无法正常工作。我的printf 很好,但它没有按频率对它们进行排序。我希望它们从最高到最低排序。

在此示例中:文件包含 -> 一二三四二三四三四四四 我得到: 两个 2 一个 1 四 4 三个 3

虽然我应该得到: 四 4 三 3 两个 2 一个 1

这里是代码。随时提供帮助!

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

#define HTABLE_SIZ 1001
#define MAX_LINE_SIZ 1024

/* Hash Table */
typedef struct node* link;
struct node { char *token; int freq; link next; };

link htable[HTABLE_SIZ] = { NULL }; /* Table of lists (#buckets) */
int size = 0; /* Size (number of elements) of hash table */

unsigned int hash (char *tok );
void insert_ht (char *data);
void clear_ht ( );
void print_ht ( );

void Process(FILE *fp);


int main(int argc, char *argv[])
{
    int i;
    FILE *fp;
    printf("prin tin for \n");
    for (i=1; i < argc; i++)
    {
        printf("prin tin fopen \n");
        fp = fopen(argv[i],"r");
        if (NULL == fp)
        {
            fprintf(stderr,"Problem opening file: %s\n",argv[i]);
            continue;
        }
        printf("prin tin process \n");
    Process(fp);
    fclose(fp);
    }
    print_ht();
    //clear_ht();
    return 0;
}


void Process(FILE *fp)
{
    const char *seperators = " ?!'\";,.:+-*&%(){}[]<>\\\t\n";

    char line[MAX_LINE_SIZ];
    char *s;
    while((fgets(line,MAX_LINE_SIZ, fp)) != NULL)
    {
        for (s=strtok(line,seperators); s; s=strtok(NULL,seperators)){
            printf("prin tin insert %s \n",s);
            insert_ht(s);
        }
            
        }
    }
    
/* Hash Function */
unsigned int hash(char *tok)
{
    printf("bike stin hash \n");
    unsigned int hv = 0;
    while (*tok)
        hv = (hv << 4) | toupper(*tok++);
    printf("VGAINEIIIIIIIIIIIIII %d \n",hv);
    return hv % HTABLE_SIZ;
}



void insert_ht(char *token)
{
    printf("bike stin insert %s \n",token);
    unsigned int hashval = hash(token);

    if (htable[hashval]==NULL){
        printf("mesa stin prwti if %u %s \n",hashval,token);
        //token = strdup(token);
        htable[hashval] = malloc(sizeof(token));
        htable[hashval]->token = token ;
        htable[hashval]->freq = 1;
        size++;
        
    }else {
        htable[hashval]->freq++;
    }
    printf("ta evale epitixws \n");
    
}



int compare(const void *elem1, const void *elem2)
{
    const struct node *p1 = elem1;    
    const struct node *p2 = elem2;
    
    if ( p1->freq < p2->freq)
      return -1;

   else if (p1->freq > p2->freq)
      return 1;

   else
      return 0;
}
void print_ht()
{
    int i, j=0;
    link l, *vector = (link*) malloc(sizeof(link)*size);
    for (i=0; i < HTABLE_SIZ; i++)
        for (l=htable[i]; l; l=l->next)
            vector[j++] = l;
        qsort(vector,size,sizeof(link),compare);
        for (i=0; i < size; i++)
            printf("%-50s\t%7d\n",vector[i]->token,vector[i]->freq);
        free(vector);
} 

【讨论】:

    【解决方案3】:

    对不起,我的英语不好。

    我认为:

    1. insert(char *token) 获取文件的一个单词并放入哈希表中。简而言之,如果这个词存在于哈希表中,你只需要增加它的频率。否则,您需要创建另一个节点并将频率设置为 1,然后将其添加到数组中。最后,每个唯一词都有一个条目。

    2. compare(const void *elem1, const void *elem2) 将被 qsort 使用。如果 elem1 = elem2 返回 0,如果 elem1 elem2 返回数字 > 0。通过将 compare 传递给 qsort,您允许 qsort 根据您自己的标准对数组进行排序。

    3. clear_ht() 可以将数组的所有值设置为 NULL,以便重新开始另一个计数?

    【讨论】:

    • 我很难弄清楚如何主要执行插入功能。我为 clear_ht() 做了这个:void clear_ht(link htable) { free(htable-&gt;token); free(htable-&gt;freq); free(htable); }
    • @Scotoner 您不需要将 htable 作为参数,因为它是一个全局变量。另外,您不需要free(htable),因为您没有对其进行malloc。 freq 也是一样,它是一个整数。但是您需要释放每个令牌,因为您将在插入函数中对它们进行 malloc,如下所示:for(i = 0; i &lt; HTABLE_SIZ; i++) { free(htable[i].token); }
    • 是的,但是如果我释放每个令牌,我不应该也释放频率吗?
    • 另外我不明白我将如何使用unsigned int hash(chat *tok) 函数。
    • @Scotoner,你不能释放没有被 malloc'd 或 calloc'd 的东西。原因是malloc在堆上分配内存,你需要自己管理这块内存。您可以阅读此内容以帮助您理解:gribblelab.org/CBootcamp/7_Memory_Stack_vs_Heap.html。所以你需要释放令牌,因为你需要 malloc 它们,因为你用*而不是[x]声明它们我只能推测关于 hash :通常,hashCode 应该是与元素关联的唯一值。因此,如果两个元素具有不同的哈希码,它们就是不同的。
    猜你喜欢
    • 2012-10-10
    • 1970-01-01
    • 2016-01-06
    • 1970-01-01
    • 1970-01-01
    • 2011-05-26
    • 2023-03-22
    • 2013-02-02
    相关资源
    最近更新 更多