【问题标题】:Hash function C散列函数 C
【发布时间】:2015-07-12 08:58:45
【问题描述】:

我在为我的哈希表实现哈希函数时遇到问题。

我想对我的单词进行哈希处理,使得 A = 1、B = 2、C = 3 等等。单词中字母的位置无关紧要,因为我们将考虑单词的排列。此外,字母的大小写在这个问题中也无关紧要,所以 a 的值 = A 的值 = 1。

对于字符串,abc = 1 + 2 + 3 = 6,bc = 2 + 3 = 5,等等。

对于 ab = 3 和 aaa = 3 的情况,我已经有了处理这种情况的方法。现在我只想获取哈希值。

我现在遇到的问题是 aaa 给我 1,而 ab 给我 2。

下面是我的代码:

int hash(char *word)
{
   int h = 1;
   int i, j;

   char *A;
   char *a;
   // an array of 26 slots for 26 uppercase letters in the alphabet
   A = (char *)malloc(26 * sizeof(char));
   // an array of 26 slots for 26 lowercase letters in the alphabet
   a = (char *)malloc(26 * sizeof(char));

   for (i = 0; i < 26; i++) {
      A[i] = (char)(i + 65); // fill the array from A to Z
      a[i] = (char)(i + 97); // fill the array from a to z
   }

   for (i = 0; i < strlen(word); i++) {
      //printf("HIT\n");
      for (j = 0; j < 26; j++) {
         // upper and lower case have the same hash value
         if (word[i] == A[j] || word[i] == a[j]) {
            h = h + j; // get the hash value of the word
            //printf("HIT 2\n");
            break;
         }
      }
   }

   printf("H: %d\n", h);

   return h;
}

【问题讨论】:

  • 还有免费的失踪...
  • 你知道tolowertoupper吗?不需要两个数组或检查。既然你有一个固定的字母表,为什么要动态分配?
  • 实际上,我根本看不到数组的原因,为什么不简单地添加字母数字(您可以从例如tolower(word[i]) - 'a' + 1 获得)。另外,如果单词中有非字母字符会怎样?
  • 这实际上让我思考......我的意思是还有其他方法我刚开始学习 C 所以我这样做是为了让事情变得简单
  • 你可以像@JoachimPileborg 建议的那样简单,使用ctype.h 中的函数进行字符分类等。 1 数组而不是 2总是更简单。但是在大写/小写转换中,你甚至不需要函数。小写字符代码只是32 大于大写,反之亦然。看看ASCII Table and Description

标签: c ascii hashtable


【解决方案1】:

我认为改变

int h = 1;

int h = 0;

h = h + j;

h = h + j + 1;

将解决问题。


另一个问题是您忘记释放malloced 内存。另外,C 中有no need to cast the result of malloc(和家人)。

这个

for (i = 0; i < strlen(word); i++) {

将在循环的每次迭代中调用strlen。这会降低程序的性能。使用

int len = strlen(word);
for (i = 0; i < len; i++) {

相反,这要快得多,因为 strlen 在每次迭代中都不会被调用。最后,sizeof(char) 是 1。所以你可以省略它。

【讨论】:

  • 你应该添加缺少的免费调用,否则代码仍然是错误的。
  • 添加了更多细节。
【解决方案2】:

h=h+j 更改为 h=h+j+1h=1h=0

您还应该释放分配的内存,因此在返回之前包含这些行:

free(A);
free(a);

但是我不明白为什么要为如此简单的任务编写如此复杂的代码。

可以编写更简单的代码:

int hash(char *word)
{
   int sum=0;
   while(*word != '\0')
   {

       if(*word >='A' && *word < 'A'+26)
            sum=sum+(*word -'A' + 1);
       else if(*word >='a' && *word < 'a'+26)
            sum=sum+(*word -'a' + 1);
       else
            return -1;

       word++;
   }

   return sum;
}

【讨论】:

  • 这是我第一次处理 ascii 数字。不过非常感谢!
  • 如果你使用'A'而不是65会更清楚。
【解决方案3】:

多个问题:

  1. 你仍然没有释放你分配的数组
  2. h 的初始值为 1 没有意义
  3. 您将索引添加到哈希中。 'A' 和 'a' 在索引 0 处,因此在这种情况下您要添加 0(所以无论您给代码提供多少 'a' 都将返回 1)
  4. 为什么是动态数组?你知道大小,它不会改变。你可以使用

    char A[26];
    char a[26]; // you can also add initialisation, e.g. = {'a', 'b', ...
    
  5. 为什么是数组?

所以,here 是快速修复,与您的代码保持密切联系。

考虑到以上所有因素,您可以简化为:

int hash(char const * string) {
  int h = 0;
  for (; *string; ++string) {
    int index = tolower(*string) - 'a' + 1;
    if ((index > 0) && (index < 27)) {
      h += index;
    }
  }
  return h;
}

Live


当只对带有非特殊字符的单词进行哈希处理时,您需要以某种方式处理调用者中被忽略的单词。

char hash(char const * string, int * h) {
  *h = 0;
  for (; *string; ++string) {
    int index = tolower(*string) - 'a' + 1;
    if ((index > 0) && (index < 27)) {
      *h += index;
    } else {
      return 0;
    }
  }
  return 1;
}

这样你就可以使用返回值来测试这个词是否应该被忽略。

【讨论】:

  • 你如何处理特殊字符?
  • 我忽略它们,就像在您的原始代码中一样。你想处理它们吗?
  • 哦,所以当我尝试你的代码时,由于某些原因,它给了我 69 分。
  • T = 20,U = 21,D = 4,E = 5,S = 19;总结得出 69,这是预期的结果。 é 是一个特殊字符,所以被忽略了。
  • 我的错我计算错误。但是,如果我想忽略整个单词而不仅仅是一个字符呢?
猜你喜欢
  • 1970-01-01
  • 2010-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-24
  • 2016-04-14
  • 2021-05-17
相关资源
最近更新 更多