封闭寻址哈希表。他们是如何调整大小的?

时间:2015-06-21 15:50:25

标签: java algorithm performance hashmap hashtable

阅读hopscotch hashing并尝试理解它是如何成为代码我意识到在线性探测哈希表变体中我们需要有一个递归方法来调整大小,如下所示:

  1. 创建现有存储桶的备份数组

  2. 分配所请求容量的新数组

  3. 遍历备份数组并重新运行每个元素以获取 新数组中元素的新位置并将其插入 新阵列
  4. 完成后释放备份阵列
  5. 代码结构如下:

    public V put(Object key, Object value) {  
       //code  
       //we need to resize)
       if(condition){  
           resize(2*keys.length);  
           return put(key, value);  
       }
       //other code
    }  
    
    private void resize(int newCapacity) {  
      //step 1 
      //step 2  
      //go over each element  
      for(Object key:oldKeys) {
        put(key, value);  
      }  
    }
    

    我不喜欢这种结构,因为我们递归调用put里面的resize 这是使用线性探测变体时调整哈希表大小的标准方法

1 个答案:

答案 0 :(得分:1)

好问题!通常,在封闭地址散列中,如跳房子散列,布谷鸟散列或静态完美散列,重新散列可能会失败,单个“重新散列”步骤可能必须坐在循环中,尝试将所有内容分配到新表中,直到它找到一种有效的方法。

您可能需要考虑使用三种方法 - put,外部可见函数rehash,内部函数和tryPut,它们会尝试添加元素,但可能会失败。然后,您可以实现这些主要用于展示的功能,并且可以进行一些优化:

public V put(Object key, Object value) {
    V oldValue = get(key);
    while (!tryPut(key, value)) {
        rehash();
    }
    return oldValue;
}

private void rehash() {
    increaseCapacity();

    boolean success;
    do {
       success = true;
       reallocateSpace();

       for (each old key/value pair) {
          if (!tryPut(key, value)) {
             success = false;
             break;
          }
       }
    } while (!success);
}

private boolean tryPut(Object key, Object value) {
   // Try adding the key/value pair using a
   // hashtable specific implementation, returning
   // true if it works and false otherwise.
}

此处不再存在任何奇怪递归的风险,因为tryPut从不调用任何其他内容。

希望这有帮助!