什么是序列中最紧凑的表示?

时间:2015-03-09 19:14:12

标签: data-structures clojure

我正在存储一个映射,我有seq个整数作为键。 hashmap非常大(100,000个键),所以我想要最紧凑的存储方法来节省RAM。

有一些选项,包括Clojure LazySeq s,向量,java.util.Arrays甚至是字符串。我不需要上述的懒惰,持久性或实习,只是将它们用作不透明的键。

是否已知此类数据的最小最小代表?

编辑,因为问题并不清楚我想使用哈希映射,因为它提供的功能。我不想要另一种抽象数据类型。我有兴趣尽量减少键的大小。

3 个答案:

答案 0 :(得分:2)

如果内存优化很重要,您可能希望使用int(或long)的Java本机数组。但是,您需要定义一个包装器类,以便完成正确的equalshashcode合同,因为Java本机数组是对象,但只是继承equalshashCode Objects。 我还没有采取任何措施,但是 - 根据密钥序列中的整数数量 - 并且知道不可变Clojure向量背后的数据结构,这可能会产生重大影响。

要执行本机数组键,可以使用java.lang.Arrays中的实用程序函数,并在Java中定义一个简单的包装器:

public final class IntKey {
    private final int[] data;

    public IntKey(int[] data) {
        if (data == null) {
            throw new NullPointerException();
        }
        this.data = data;
    }

    @Override
    public boolean equals(Object other) {
        if (!(other instanceof IntKey)) {
            return false;
        }
        return Arrays.equals(data, ((IntKey)other).data);
    }

    @Override
    public int hashCode() {
        return Arrays.hashCode(data);
    }
}

或者使用deftype在Clojure中执行此操作:

(deftype IntKey [^ints data]
  java.lang.Object
  (equals [this other] 
    (java.util.Arrays/equals data (.data other)))
  (hashCode [this] 
    (java.util.Arrays/hashCode data)))

然后测试原生数组不是好键:

(def k1 (int-array [1 2 3]))
(def k2 (int-array [4 5 6]))
(def k3 (int-array [1 2 3])) ;; same sequence as k1

(def h (hash-map ik1 "hello" ik2 "good" ik3 "bye"))

user> (map h [ik1 ik2 ik3])
user> ("hello" "good" "bye")  ;; argh ik1 and ik3 should yield the same value

IntKey中包装int数组并重新定义地图:

(def ik1 (IntKey. k1))
(def ik2 (IntKey. k2))
(def ik3 (IntKey. k3))

(def h (hash-map ik1 "hello"  ik2 "good" ik3 "bye"))

user> (map h [ik1 ik2 ik3])
("bye" "good" "bye") ;; ok
user> (count h)
2

注意:您可能希望"缓存"包装器类中的哈希码值,每个序列只计算一次。

答案 1 :(得分:0)

这实际上取决于您需要对此数据执行的操作。最常见的解决方案是[[set,value],...],尽管它并不比hashmap好得多。可能是时候转向外部K / V了吗?

答案 2 :(得分:0)

如前所述,这实际上取决于您需要对数据执行的操作。

例如,如果您不介意某种程度的误报(但没有假阴性),您可以使用bloom filters,或者,如果键是静态的,您可以使用minimal perfect hash function,你可以用来访问数组或文件。

<强>更新

布隆过滤器确实用于表示集合而不是映射。但是,我发现了一篇有趣的论文,概括了bloom filters into maps。虽然没有找到它的任何实现。