【问题标题】:Word frequency hash table词频哈希表
【发布时间】:2016-01-06 18:26:10
【问题描述】:

好的,我有一个项目需要我有一个动态哈希表来计算文件中单词的频率。我必须使用 java,但是,我们不允许使用任何内置数据类型或内置类,除了标准数组。此外,我不允许在 Internet 上使用任何已知速度快的哈希函数。我必须制作自己的哈希函数。最后,我的导师还希望我的表从大小“1”开始,并且每次添加新键时大小加倍。

我的第一个想法是对组成单词的字母的 ASCII 值求和,并用它来做一个散列函数,但是具有相同字母的不同单词将等于相同的值。

我该如何开始? ASCII 的想法是否正确?

【问题讨论】:

  • 可以利用字母在单词中的位置来改进散列函数。
  • 如果多个单词创建相同的哈希值就可以了。哈希不应该是唯一的。事实上,如果被散列的数据大于散列,它就不可能是唯一的。哈希确定密钥存储在哪个桶中,但随后执行相等检查以确保
  • 如果每次添加新键时将数组的大小加倍,添加 32 个键将导致数组有 40 亿个条目宽:/ - 也许它们意味着每次填满时大小都会加倍

标签: java hash


【解决方案1】:

散列表不应该具有一般值和散列之间的一对一映射。哈希表预计会发生冲突。也就是说,散列函数的域应该大于范围(即散列值)。然而,一般的想法是你想出一个哈希函数,其中冲突的概率非常小。如果您的散列函数是统一的,即,如果您将其设计为每个可能的散列值具有相同的生成概率,那么您可以通过这种方式最大限度地减少冲突。

发生碰撞并不是世界末日。这只是意味着您必须搜索该哈希的值列表。如果你的散列函数很好,那么总体上你的查找性能应该仍然是 O(1)。

生成散列函数本身就是一个主题,没有一个答案。但是,您可以从使用字符串中字符的按位表示开始,并对它们执行某种卷积操作(旋转、移位、异或)。您可以基于某些初始种子值以某种方式执行这些操作,然后将散列的第一步的输出用作下一步的种子。这样,您最终可以放大卷积的效果。

例如,假设您得到字符A,即十六进制的41,或二进制的0100 0001。您可以指定每个位来表示某种操作(可能位 0 为 0 时为 ROR,为 1 时为 ROL;位 1 为 0 时为 OR,为 1 时为 XOR,等等) .您甚至可以根据值本身决定要进行多少卷积。例如,您可以说下半字节指定您将向右旋转多少,而上半字节指定您将向左旋转多少。然后,一旦获得最终值,您将使用它作为下一个字符的种子。这些只是一些想法。发挥你的想象力,看看你会得到什么!

【讨论】:

    【解决方案2】:

    不管你的哈希函数有多好,你总会遇到需要解决的冲突。

    如果你想通过使用 ASCII 值来保持你的方法,你不应该只添加值,这会导致很多冲突。您应该使用值的力量,例如对于“Help”这个词,您只需像:'H' * 256 + 'e' * 256 + 'l' * 256² + 'p' * 256³。或者在伪代码中:

    int hash(String word, int hashSize)
        int res = 0
        int count = 0;
        for char c in word
            res += 'c' * 256^count
            count++
            count = count mod 5
        return res mod hashSize
    

    现在您只需编写自己的 Hashtable:

    class WordCounterMap
        Entry[] entrys = new Entry[1]
    
        void add(String s)
            int hash = hash(s, entrys.length)
            if(entrys[hash] == null{
                Entry[] temp = new Entry[entry.length * 2]
                for(Entry e : entrys){
                    if(e != null)
                        int hash = hash(e.word, temp.length)
                        temp[hash] = e;
                entrys = temp;
                hash = hash(s, entrys.length)
            while(true)
                if(entrys[hash] != null)
                    if(entrys[hash].word.equals(s))
                        entrys[hash].count++
                        break
                else
                    entrys[hash] = new Entry(s)
                hash++
                hash = hash mod entrys.length
    
        int getCount(String s)
            int hash = hash(s, length)
            if(entrys[hash] == null)
                return 0
            while(true)
                 if(entrys[hash].word.equals(s))
                     entrys[hash].count++
                     break
                 hash++
                 hash = hash mod entrys.length
    
    
    class Entry
        int count
        String word
    
        Entry(String s)
            this.word = s
            count = 1
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-31
      • 2015-09-27
      • 2023-03-27
      • 2017-05-11
      • 1970-01-01
      • 2012-09-16
      • 2013-03-21
      • 2021-02-13
      相关资源
      最近更新 更多