【问题标题】:hash table for strings in c++C++中字符串的哈希表
【发布时间】:2013-04-07 11:21:11
【问题描述】:

我过去做过一个关于哈希表的小练习,但用户给出了数组大小,结构也是这样的(所以用户每次都给出一个数字和一个单词作为输入)

struct data
{
   int key;
   char c[20];
};

所以这很简单,因为我知道数组大小,而且用户说他将提供多少项作为输入。我的做法是

  • 散列用户给我的密钥
  • 在数组中找到位置数组[hashed(key)]
  • 如果它是空的,我会把数据放在那里
  • 如果不是,我会把它放在我能找到的下一个空闲位置。

但现在我必须制作倒排索引,并且我正在重新搜索,以便为它制作一个哈希表。所以单词将从大约 30 个 txt 中收集,它们会非常多。 那么在这种情况下,数组应该有多长?我怎样才能散列单词?我应该使用带有开放寻址或链接的hasing。练习说如果我们在网上找到它,我们可以使用哈希表。但我更喜欢自己理解和创造它。任何线索都会帮助我:)

在这个练习(使用哈希表的倒排索引)中,结构看起来像这样。 数据类型是我将创建的哈希表的类型。

struct posting
{
    string word;
    posting *next
}

struct data
{
    string word;
    posting *ptrpostings;
    data *next
};

【问题讨论】:

  • 查看聊天菜单 :)

标签: c++ hashmap hashtable


【解决方案1】:

您可以选择任何方式进行散列。假设字符串是 ABC。您可以使用散列作为 A=1, B=2, C=3, Hash = 1+2+3/(length = 3) = 2。但是,这是非常原始的。

数组的大小将取决于您部署的散列算法,但最好选择为每个字符串返回确定长度散列的算法。例如,如果您选择使用 SHA1,您可以安全地为每个哈希分配 40 个字节。请参阅Storing SHA1 hash values in MySQL 阅读算法http://en.wikipedia.org/wiki/SHA-1。我相信它可以安全使用。

另一方面,如果只是为了一个简单的练习,你也可以使用 MD5 哈希。我不建议在实际用途中使用它,因为它的彩虹表很容易获得:)

---------编辑-------

你可以尝试这样实现::

#include <iostream>
#include <string>
#include <stdlib.h>
#include <stdio.h>
#define MAX_LEN 30
using namespace std;

typedef struct
{
    string name; // for the filename
    ... change this to your specification
}hashd;

hashd hashArray[MAX_LEN]; // tentative

int returnHash(string s)
{
    // A simple hashing, no collision handled
    int sum=0,index=0;
    for(string::size_type i=0; i < s.length(); i++)
    {
        sum += s[i];
    }
    index = sum % MAX_LEN;
    return index;
}

int main()
{
    string fileName;
    int index;
    cout << "Enter filename        ::\t" ;
    cin >> fileName;
    cout << "Enter filename is     ::\t" + fileName << "\n";
    index = returnHash(fileName);
    cout << "Generated index is ::\t" << index << "\n";
    hashArray[index].name = fileName;
    cout << "Filename in array    ::\t" <<hashArray[index].name ;
    return 0;
}

然后,要实现 O(1),只要您想获取文件名的内容,只需运行 returnHash(filename) 函数。它将直接返回数组的索引:)

【讨论】:

  • 首先感谢您的回答:)。现在我检查了一个 MD5 生成器,对于字符串 caesar 它返回 b712916d8bfc1718a431c7b4fa280ae6 。我将如何使用 b712916d8bfc1718a431c7b4fa280ae6 进入阵列的右侧插槽?此外,我仍然对查找数组的大小以及是否必须不时调整它的大小感到困惑。在我当前的练习中,我必须处理这么多字符串(30 个带有故事的 txt),数组应该多长?
  • 您所描述的是获取 O(1) tie 中值的操作,对吗?为此,您可以使用从字符串返回数组索引的算法。如上面的示例。然后,当你得到“ABC”时,你可以直接进入索引[2]。请记住,这很有可能发生冲突,你将不得不采用开放散列或封闭散列技术。另外,您正在为故事文件的名称创建哈希,对吗?您能告诉我为什么在这种情况下选择数组中的 c[20] 和键吗?什么是 c[20]?我可以更好地回答这个问题
  • 我想要的时间是 O(1) 对。例如,使用您编写的散列算法,我的数组应该有多少个槽?你是对的,我还将包括故事的名称。好吧,我使用了 c[20],因为用户给出了一个键和一个单词,而这个单词将少于 20 个字母。
  • 如果你知道故事的数量,那么你可以初始化结构数组的数量。至于单词,单词的作用是什么?如果不需要这个词,甚至不需要结构。只需根据文件名计算索引,然后将数组分配给那个
  • 如果您知道故事的数量,那么您可以将结构数组的数量初始化为那个?主要思想是对我将阅读的所有 txt 的所有单词进行倒排索引(字典)。那么如何通过故事数知道数组的大小? :S 对不起我的英语
【解决方案2】:

哈希表可以实现为一个简单的二维数组。问题是如何计算要存储的每个项目的唯一键。有些东西在数据中内置了键,而对于其他东西,您必须计算一个:上面建议的 MD5 可能正好满足您的需求。

您需要解决的下一个问题是如何布局或调整哈希表的大小。您最终需要通过一些测试来调整自己的需求。您可以从设置数组的第一个维度开始,其中包含 255 个条目——一个用于 MD5 哈希的前 2 位数字的每个组合。每当发生碰撞时,您都会在数组的第 2 维索引处的第 1 维索引处添加另一个条目。这意味着您将静态定义一维数组,同时根据需要动态分配二维条目。希望这对你和我一样有意义。

在进行查找时,您可以立即使用 MD5 哈希的第一个 2 位找到正确的第一个维度索引。然后沿二维的相对短线性搜索将快速将您带到您要寻找的项目。

您可能会从实验中发现,如果您的数据集足够大,使用更大的第一个维度(使用 MD5 哈希的前 3 位)会更有效。根据所涉及文本的大小以及它们对词典的使用分布,您的结果可能会决定您的某些架构。

另一方面,您可能只是从小处着手,并构建一些智能来自动调整表格的大小和布局。如果您的桌子在任一方向上都过长,性能就会受到影响。

【讨论】:

  • 谢谢你,这肯定有点暴露。您建议将 hastable 与链接一起使用。我不明白的是例如 MD5HASH("caesar") 返回 b712916d8bfc1718a431c7b4fa280ae6 所以它返回的前两个是 b7 对吗?那就是我将去位置数组[b7]?抱歉,如果我问的内容过于转储,但我仍然对这个 b712916d8bfc1718a431c7b4fa280ae6 感到困惑,因为在我的其他练习中,它只返回了数字
  • 是的,我提出了一个带有链接的哈希表。将哈希数组中的每个条目视为一个桶,其中包含与给定哈希计算冲突/绑定的动态增长的项目集合。要回答您的问题:是的,您可以在示例中将“caesar”条目放入“bucket”hasharray[b7]。
猜你喜欢
  • 2019-07-29
  • 2011-04-28
  • 1970-01-01
  • 2013-12-19
  • 1970-01-01
  • 1970-01-01
  • 2012-10-07
  • 2018-07-16
  • 2013-03-13
相关资源
最近更新 更多