散列三个整数集的最佳方法

时间:2013-12-11 20:56:54

标签: java optimization data-structures hashmap tuples

我正在尝试编写一个程序,可以快速找到与带有通配符和已知字母的字符串匹配的所有单词。例如,L * G将返回LOG,LAG,LEG。我正在寻找能让我快速查找的东西,但我并不关心创建树的时间。

我的想法是"三重奏"的Hashmap映射到字符串的ArrayList:基本上是所有字符串的列表,它匹配某个索引,该索引处的字符和长度的条件。

但我现在的问题是为这些"三重奏"生成一个好的哈希函数。这样每个三联体都是独一无二的。

这是我现在所拥有的代码。

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class CWSolutionT {
HashMap<Triple, ArrayList<String>> tripleMap = new HashMap<Triple, ArrayList<String>>();

public CWSolutionT(List<String> allWords) {
    for (String word : allWords) {
        for (int letter = 0; letter < word.length(); letter++) {
            ArrayList<String> tempList = new ArrayList<String>();
            Triple key = new Triple(letter, word.charAt(letter),
                    word.length());
            if (tripleMap.get(key) == null) {
                tempList.add(word);
                tripleMap.put(key, tempList);
            } else {
                tempList = tripleMap.get(key);
                tempList.add(word);
                tripleMap.put(key, tempList);
            }
        }
    }
}

public List<String> solutions(String pattern, int maxRequired) {
    List<String> sol = new ArrayList<String>();
    List<List<String>> solList = new ArrayList<List<String>>();
    int length = pattern.length();
    for (int i = 0; i < length; i++) {
        if (pattern.charAt(i) != '*') {
            Triple key = new Triple(i, pattern.charAt(i), pattern.length());
            solList.add(tripleMap.get(key));
        }
    }
    if (solList.size() == 0) {
        // implement later
    }

    if (solList.size() == 1)
        return solList.get(0);

    for (List<String> list : solList) {
        sol.retainAll(list);
    }
    return sol;
}

private class Triple {
    public final int index;
    public final char letter;
    public final int length;

    public Triple(int ind, char let, int len) {
        index = ind;
        letter = let;
        length = len;
    }

    public boolean equals(Object o) {
        if (o == null)
            return false;
        if (o == this)
            return true;
        if (!(o instanceof Triple)) {
            return false;
        }
        Triple comp = (Triple) o;
        if (this.hashCode() == comp.hashCode())
            return true;
        return false;
    }

    public String toString() {
        return "(" + index + ", " + letter + ", " + length + ")";
    }

    public int hashCode() {
        return (int) (.5 * (index + letter + length)
                * (index + letter + length + 1) + letter + length);
    }
}
}

3 个答案:

答案 0 :(得分:4)

您必须在Tuple班级

中覆盖hashCode()

答案 1 :(得分:0)

HashMap需要equalshashCode的实现,并且您没有覆盖其中任何一个。现在你的地图基本上只是检查对象标识(someOldObject == someNewObject)。

看起来您已尝试实施等号方法但签名错误,Object#equalsObject作为参数而您的Tuple取而代之为<{1}} EM>过载。这个问题的答案有一些实现equals和hashCode的技巧:What issues should be considered when overriding equals and hashCode in Java?

答案 2 :(得分:0)

一般来说,不可能将两个int s成两个。 Cantor配对函数适用于无限域,但将其转移到int s无处可去。

您的输入是三(int, char, int),理论上可以解释2**32 * 2**16 * 2**32 = 2**80种可能性,这显然无法主观映射到仅包含2**32元素的集合。

借助一些关于输入值的知识,你可以做得更好,但可能还不够好。例如,您知道indexlength都是非负数,这会使您的域缩小四倍......但这没什么。

如果您知道indexlength都小于256,则可以通过

进行映射
public int hashCode() {
    return index + 256 * length + 256 * 256 * letter;
}

此表达式可以更有效地编写为

index + (length << 8) + (letter << 16)

但您可以将它留给JIT编译器。

很有可能你不能充分减少域名,然后我建议让它成为现实。只是比较字段...你可以试着把它装进很久但不是全部the root of all evil

请注意你的

public int hashCode() {
    return (int) (.5 * (index + letter + length)
            * (index + letter + length + 1) + letter + length);
}

太糟糕了....你正在使用配对三件事!元组(0, 'A', 1)(0, 'B', 0)具有相同的hashCode,因此您的equals返回true。实际上,您需要配对indexletter + length,而您必须使用两种配对。