【问题标题】:HashMap (Open Addressing) Implementation VERY slowHashMap(开放寻址)实现非常慢
【发布时间】:2019-12-01 21:01:03
【问题描述】:

出于某种原因,我使用开放寻址的 HashMap 实现在处理大型数据集时运行非常缓慢,但我无法弄清楚究竟是什么原因。谁能提供一些见解?我只是一个数据结构的学生,想弄清楚为什么我的数据结构效率如此之低。

我在较小的数据集上运行它,它可以在我期望的时间内运行,但是一旦我加速它就失败了。

import java.util.ArrayList;
import java.util.List;
import java.lang.Math;
import java.util.Collections;
import java.lang.reflect.Array;
/**
 * @author Cameron Berger
 * HASHMap if a data structure which is suppose to be faster than an AVL tree
 * for set() and get(), however, I was unsucessful in this. But it works!
 */
public class HASHMap<K extends Comparable<K>,V> implements Map<K,V>{
  private class Node{
    public K k;
    public V val;

    public Node(K key, V value) {
      k      = key;
      val    = value;
    }
  }

  //time to implement
  private List<Node> arr;
  private int numKeys;
  private int size;
  private double loadFactor = 0.5;
  /**
   * Constructor for HASHMap
   **/
  public HASHMap(){
    size = 16;
    arr = new ArrayList<Node>(Collections.nCopies(size, null));
    numKeys = 0;
  }

  public V get(K key){
    int index = Math.abs(key.hashCode())%size;
    Node n;
    for(int i=index; ; i=(i+1)%size){
      n = arr.get(i);
      if (n == null)
        return null;
      else if(key.compareTo(n.k)==0)
        return n.val;
    }
  }

  public void set(K key, V value){
    int index = Math.abs(key.hashCode())%size;
    Node n;
    for(int i=index; ; i=(i+1)%size){
      n = arr.get(i);
      if (n == null){
        Node temp = new Node(key, value);
        arr.set(i, temp);
        numKeys++;
        break;
      }
    }
    if(Double.compare((numKeys/size),loadFactor)>0){
      this.reinitialize();
    }
  }
  /**
   * reinitialize reinitializes the HashMap if the loadFactor condition is met
   * or there is too much spill over
   **/
  private void reinitialize(){
    int nsize = size*2;
    List<Node> nArr = new ArrayList<Node>(Collections.nCopies(nsize, null));
    Node temp;

    for(int i=0; i<size; i++){
      temp = arr.get(i);
      if(temp!=null){
        K key = temp.k;
        int index = Math.abs(key.hashCode())%nsize;
        for(int j=index; ; j=(j+1)%nsize){
          Node n = nArr.get(j);
          if(n==null){
            nArr.set(j, temp);
            break;
          }
        }
      }
    }
    this.size = nsize;
    this.arr = nArr;
  }

  public int size(){ return numKeys; }

  public List<K> keys(){
    List<K> keylist = new ArrayList<K>();
    for(int i=0; i<size; i++){
      Node n = arr.get(i);
      if(n!=null)
        keylist.add(n.k);
    }
    return keylist;
  }

  public List<V> values(){
    List<V> valuelist = new ArrayList<V>();
    for(int i=0; i<size; i++){
      Node n = arr.get(i);
      if(n!=null)
        valuelist.add(n.val);
    }
    return valuelist;
  }
}

【问题讨论】:

  • 不确定您是如何测试的,因为您缺少许多方法,并且其中一些方法与Map 接口中的签名不匹配。

标签: java data-structures hashmap


【解决方案1】:

这部分好像有问题:

    if(Double.compare((numKeys/size),loadFactor)>0){
      this.reinitialize();
    }

由于numKeyssize 都是整数,所以这是整数除法——即向下舍入。因此,当numKeyssize 相等时,除法的结果只会大于loadFactor,这实际上意味着您的类的行为类似于负载因子为1 而不是0.5 的哈希表。这会导致您的开放寻址方案恶化为 O(n) 复杂度而不是 O(1)。

解决方案是更改此条件,以便正确进行比较。首先,当你除整数时要小心,但你希望答案是双精度数;您需要在除法之前转换为加倍。其次,当您可以使用&lt;&gt; 时,不要使用Double.compare。固定版本如下所示:

    if((double) numKeys / size > loadFactor) {
        this.reinitialize();
    }

或者,为了完全避免分裂,您可以等效地测试numKeys &gt; loadFactor * size

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-05-29
    • 1970-01-01
    • 2015-11-02
    • 1970-01-01
    • 2018-01-05
    • 1970-01-01
    • 2011-05-02
    相关资源
    最近更新 更多