2

我当前的解决方案使用多维数组,是否存在更简单的解决方案?我想在 O(1) 时间内访问散列对象,并希望充分利用内存空间,因此需要完美的散列。

public final class PerfectHash {

private Object[][][] hashtable = new Object[26][26][26];

public void storeObjectAgainst3letterStringKey(Object o, String s){

    int[] coord = stringToCoord(s);
    hashtable[coord[0]][coord[1]][coord[2]] = o;

}

public Object get(String s){
    int[] coord = stringToCoord(s);
    return hashtable[coord[0]][coord[1]][coord[2]];
}

private int[] stringToCoord(String s){
    if (!s.matches("[a-z][a-z][a-z]")){
        throw new IllegalStateException("invalid input, expecting 3 alphabet letters");
    }
    // 1-26
    // 1-26
    // 1-26
    String lowercase = s.toLowerCase();

    // 97-122 integers for lower case ascii
    int[] coord = new int[3];
    for (int i=0;i<lowercase.length();++i){
        int ascii = (int)lowercase.charAt(i);
        int alpha = ascii - 97; // 0-25     
        coord[i] = alpha;
    }
    return coord;
}
}
4

3 回答 3

3

您甚至不需要先转换字符串。如果你的三个字符是小写的,你可以这样做。

public static int hashFor(String s) {
    assert s.length() == 3 && isLower(s.charAt(0)) && isLower(s.charAt(1)) && isLower(s.charAt(2));

    return ((s.charAt(0) - 'a') * 26 + s.charAt(1) - 'a') * 26 + s.charAt(2) - 'a';
}

// check a-z not all lowercase letters.
public static boolean isLower(char ch) {
    return ch >= 'a' && ch <= 'z';
}

稍微优化的版本是

public static int hashFor(String s) {
    return s.charAt(0) * (26 * 26) + s.charAt(1) * 26 + s.charAt(2) - ('a' * (26*26+26+1));
}

只有数字的计算将由编译器优化。

顺便说一句,使用 match() 可能比其他所有方法慢 100 倍。;)

如果您已经确定它必须为小写,则无需转换为小写。

于 2014-06-26T10:38:11.027 回答
2

您可以只使用一维数组而不是 3 维数组。

然后添加一个函数

public Object get(String s){
    int[] coord = stringToCoord(s);
    int hashindex = (coord[0]*26 + coord[1])*26 + coord[2];
    return hashtable[hashindex];
}

此外,查看trie数据结构,它们对于有效的字符串查找很有用。

于 2014-06-26T10:29:15.327 回答
1

唯一可能更有效的方法是将您的字符串直接映射到单个哈希值并在一维数组中进行查找:

public final class PerfectHash {
  private Object[] hashtable = new Object[26*26*26];
  private int getHash(String s) {
      char a = s.charAt(0) - 'a', b = s.charAt(1) - 'a', c = s.charAt(2) - 'a';
      if(s.length() != 3 || a >= 26 || b >= 26 || c >= 26)
        throw new IllegalStateException("invalid input, expecting 3 alphabet letters");
      return (a*26+b)*26+c;
  }
  public object get(String s) {return hashtable[getHash(s)];}
  public void set(String s, Object o) {hashtable[getHash(s)] = o;}
}
于 2014-06-26T10:51:27.653 回答