哈希函数/代码

时间:2016-04-10 20:26:30

标签: c++ hash

所以我只是在学习(或尝试)一些关于哈希的知识。我尝试制作散列函数,但是我把数据保存到的地方很困惑。我试图计算碰撞次数并将其打印出来。我制作了3个不同的文件,一个包含10,000个单词,20,000个单词和30,000个单词。每个单词只有10个随机数/字母。

long hash(char* s]){
    long h;
    for(int i = 0; i < 10; i++){
      h = h + (int)s[i];
    }
     //A lot of examples then mod h by the table size
     //I'm a bit confused what this table is... Is it an array of
     //10,000 (or however many words)?

    //h % TABLE_SIZE
    return h
  }

  int main (int argc, char* argv[]){
    fstream input(argv[1]);
    char* nextWord;
    while(!input.eof()){
      input >> nextWord;
      hash(nextWord);
    }
  }

这就是我现在拥有的东西,但是我无法弄清楚表格究竟是什么,正如我在上面的评论中所说的那样......它是我主要的预定义数组吗?在它的话?例如,如果我有一个10个字的文件,我可以在我的主文件中创建一个大小为10的数组吗?然后如果/当我返回h时,让我们说顺序为:3,7,2,3

第四个字是碰撞,对吗?当发生这种情况时,我将1加入碰撞,然后加1,然后检查插槽4是否也已满?

感谢您的帮助!

2 个答案:

答案 0 :(得分:3)

散列的要点是对您存储的每个元素进行恒定的时间访问。我将尝试用简单的例子来解释。

首先,您需要知道需要存储多少数据。例如,如果您想存储数字,并且您知道,您将不会存储大于10的数字。最简单的解决方案是创建一个包含10个元素的数组。该数组是您的“表格”,您可以在其中存储您的数字。那么如何实现这种惊人的恒定时间访问?哈希函数!重点是返回一个数组的索引。让我们创建一个简单的:如果你想存储7,你只需将它保存到位置7的数组。每次,你想看看,对于元素7,你只需将它传递给你的函数和bzaah!你在恒定的时间内获得了你的元素的位置!但是如果你想存储价值7的更多元素呢?您的简单散列函数为每个元素返回7,现在它已经占据了我的位置!怎么解决?嗯,解决方案不多,最简单的是:

1:链接 - 您只需将元素保存在第一个空闲位置即可。这有很大的缺点。想象一下,你想要删除一些元素......(这是方法,你描述的是

2:链接列表 - 如果您在某些链接列表上创建指针数组,则可以轻松地在链接列表的末尾添加新元素,即位置7!

这两种简单的解决方案都有其缺点和缺点。我想你可以看到它们。正如@rwols所说,你不必使用数组。您也可以使用树或成为真正的C ++主服务器,并使用unordered_mapunordered_set自定义哈希函数,这非常酷。还有一个名为trie的结构,当你想要创建某种字典时(这里很难知道,你需要存储多少个字),这个结构很有用。

总结一下。你必须知道,有多少东西,你不想存储,然后,创建理想哈希功能,它涵盖了适当大小的数组,在完美的世界中,它必须具有统一的索引分布,没有合作。 (这是非常困难的,在现实世界中,我猜,这是不可能的,所以越少越好,越好。)

你的哈希函数非常糟糕。它会有很多的分数(比如字符串“ab”和“ba”)而且,你需要修改它,m 是你数组的大小(也就是表格),所以你可以将它保存到某个数组,你可以从中获利。 modus是一种简单化函数的方法,因为函数必须“适合”在表中,你在开头指定,因为你不能将元素保存在位置11,12,..如果你有10个数组。

良好的散列函数应该如何?嗯,有比我更好的消息来源。一些example(警告!它在Java中)

对于你的例子:你根本无法将10k甚至更多的单词保存到10号表中。这会产生很多冲突,你失去了散列函数的主要好处 - 可以不断访问你保存的元素。 / p>

您的代码看起来如何?像这样:

int main (int argc, char* argv[]){
    fstream input(argv[1]);
    char* nextWord;

    TypeOfElement table[size_of_table];
    while(!input.eof()){
      input >> nextWord;
      table[hash(nextWord)] = // desired element which you want to save
    }
  }

但是我想,你的目标不是在某处保存某些东西,而是要计算分数。另请注意,上面的代码不能解决问题。如果您想计算colices,请创建整数table整数并将其初始化为零。然后,只需增加存储在索引上的值,该值由哈希函数返回,如下所示:

table[hash(nextWord)]++;

我希望我帮助过。请说明您还想知道什么。

答案 1 :(得分:1)

如果需要哈希表,那么正如其他人所说的std::unordered_map在大多数情况下都可以使用。现在,如果你需要更强大的东西,因为有大量的入口基础,那么我建议你研究一下tries。尝试结合(矢量阵列)插入,(散列)和放大器的概念。链接列表。运行时间接近于O(M),其中M是字符串中字符的数量,如果您正在散列字符串。它有助于消除碰撞的机会。而且,添加到trie结构越多,在打开和创建某些节点时,工作就越少。一个缺点是tries需要更多内存。这是一张图trie

现在你的trie可能因阵列的大小而有所不同,但是你的整体概念和构造是相同的。如果你正在做一个单词 - 定义查找,那么你可能需要一个26或几个数组,用于每个可能的散列字符。