繁体   English   中英

HashMap(开放寻址)实现非常慢

[英]HashMap (Open Addressing) Implementation VERY slow

出于某种原因,我使用开放寻址的 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;
  }
}

看起来这部分有问题:

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

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

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

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

或者,为了完全避免除法,您可以等效地测试是否numKeys > loadFactor * size

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM