【问题标题】:C smdb hash value % tableSize evaluating to same value repeatedly? (With different input.)C smdb哈希值%tableSize重复评估相同的值? (使用不同的输入。)
【发布时间】:2017-09-07 05:09:50
【问题描述】:

尝试使用 smdb 算法创建哈希表(因为我听说不要尝试自己编写哈希表是明智之举。)我确定我做错了。我有没有提到我是 C 的新手?

我的 hashFunction() % size 在第一次调用时首先返回一个像 35 这样的数字,然后在第 2 次调用、第 3 次调用、第 4 次调用...时,它会无限返回 65。我只是将这些数字用作任意示例。在尝试用调试器解决之后,我注意到 hashFunction 返回不同的长整数,但它们都以相同的最后 2 个数字结尾......就像这样......

4460735 4526335 4591935

所以我想这就是为什么当我散列 % size 时,每次都会得到相同的输出。这违背了均匀分布密钥的想法,对吧?

请对我放轻松。我知道 SO 上的人有多野蛮。

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

typedef struct node
{
    char* str;
    struct node* next;
} 
node;

void insertItem(char* number, node** list);
unsigned long hashFunction(char* str);

int main(void)
{

    int size = 100;
    int index = 0;

    node* buckets[size];

    for (int i = 0; i < size; i++)
    {
        char c = i + 'A';
        index = hashFunction(&c) % size;
        insertItem(&c, &buckets[index]);
    }

}

void insertItem(char* str, node** list)
{
    node* newItem = malloc(sizeof(node));
    newItem->str = str;
    newItem->next = *list;
    *list = newItem;
}

unsigned long hashFunction(char* str)
{
    //sdbm hash function adapted (incorrectly?) from here: http://www.cse.yorku.ca/~oz/hash.html
    unsigned long hash = 0;
    int c;

    while ((c = *str++))
        hash = c + (hash << 6) + (hash << 16) - hash;

    return hash;
}

【问题讨论】:

标签: c hash linked-list


【解决方案1】:

问题是您对字符而不是字符串进行测试。

如果你用真实的字符串给你的算法提供一些东西,那么你会得到更重要的东西。例如,使用以下代码更改您的代码:

char mystring[] = "Any string will do !";

for (int i = 0; i < size; i++)
{
    mystring[0] = i; // simple hack to change the string a bit, well ... a byte ;)
    index = hashFunction(mystring) % size;
    insertItem(mystring, &buckets[index]);
}

如果你打印index,你会得到一个更合适的索引。

编辑:

真正的问题是你的散列函数被设计成获取一个 C 字符串作为参数(一个 char* 指向一个必须以 null 结尾的缓冲区,即以'\0' 结尾)。当您给出单个字符的地址时,第一次取消引用是可以的,但是使用指向不是真正分配对象的东西的下一个地址(++ 之后)是undefined behavior

致谢:请参阅 moooeeeep answer 和 cmets。

【讨论】:

  • 您好,感谢您的回复。它实际上只在 2 个桶中结束,其中 1 个桶只有 1 个列表项,其余的都在第 2 个桶中。我会用更长的字符串再试一次,看看效果如何,就像你建议的那样。
  • 当我用你的代码打印索引时,我得到一个 65,然后是很多 35,然后不是那么多 7。问题是你的数据类型是 char 而不是 char*
  • 当我将 char c = i + 'A' 替换为您建议的内容(并删除使用 c 的函数参数上的 &)时,我收到此错误:“将 'int' 添加到字符串不附加到字符串 [-Werror,-Wstring-plus-int]"
  • 我使用 -std=gnu99 进行简单的字符串连接...使用 sprintf
  • 好的,谢谢,我试试 sprintf。如果可行,我会将其标记为答案。
【解决方案2】:

散列函数需要一个指向空终止字符串的指针作为输入参数。您将指针传递给单个字符。该函数然后迭代无效内存,直到它到达一个随机的空字节。

char c = i + 'A';
index = hashFunction(&c) % size;

你需要传递一个指向字符串的指针。例如:

char arr[] = "Hello World";
index = hashFunction(arr) % size;

还可以考虑将size 设置为素数以增加随机性。进一步阅读:

【讨论】:

  • 非常有帮助 :) 我喜欢你解释它的方式,并提供了超出我的问题范围的一些额外帮助,我会将其标记为答案,但神经首先指出我的疏忽:P跨度>
  • @moooeeeep:您对类型是正确的,但我不确定通过随机内存的迭代。我的 C 有点生锈了……
  • @neuro 当指针在循环条件the behavior is undefined 中递增和取消引用时。无论内存当前具有什么值,都不允许取消引用不指向对象的指针。没有触发分段错误只是一个巧合。
  • @moep:是的,确实如此。我忽略了那部分。感谢您的评论。我将编辑我的答案以反映这一点。
猜你喜欢
  • 1970-01-01
  • 2021-10-25
  • 1970-01-01
  • 2020-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多