HashSet / HashMap等效的TreeSet / TreeMap(自定义哈希)

时间:2011-12-16 14:26:49

标签: java map set hashtable

TreeSet有一个带比较器的构造函数,这意味着即使您存储的对象本身不是Comparable个对象,也可以提供自定义比较器。

是否有类似的无序集实现? (例如HashSet<T>的替代方法,它采用“hasher”对象计算equals()hashCode()对象T可能与对象自己的实现不同?)

C ++ std::hash_set给你这个,只是想知道是否有适合Java的东西。


编辑:@Max提出了关于equals()的良好技术观点 - 足够公平;通过Map.containsKey() TreeMapHashMap键确实如此。但是否有其他众所周知的数据结构可以通过自定义哈希来组织?

4 个答案:

答案 0 :(得分:9)

不,Collections规范不支持“hasher”对象。您当然可以实现支持此功能的集合,但另一种方法是将Hasher视为您在HashSet中存储的包装对象。

Set<HasherWrapper<Foo>> set = new HashSet<HasherWrapper<Foo>>();
set.add(new HasherWrapper(foo));
...

然后包装类看起来像:

private class HasherWrapper<T> {
    T wrappedObject;
    public HasherWrapper(T wrappedObject) {
        this.wrappedObject = wrappedObject;
    }
    @Override
    public int hashCode() {
        // special hash code calculations go here
    }
    @Override
    public boolean equals(Object obj) {
        // special equals code calculations go here
    }
}

答案 1 :(得分:4)

标准库中没有这样的实现,但它不会阻止您自己滚动。这是我经常想要拥有的东西。

请参阅http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4771660,原因如下:

  

我们希望避免这种复杂性。我们认真地接受了这个想法   在收集框架设计时,但拒绝了它。该   功率重量比似乎很低。我们觉得平等就是你   想要95%的时间; ==,4%;和别的东西1%。写得明智   当等式谓词时,批量操作的合同非常棘手   不同。

答案 2 :(得分:1)

不,没有,也没有规范。而且,你误解了TreeSet使用Comparator的方式。

来自TreeSet Javadoc

  

注意由一组维护的排序(无论是否显式   比较器提供)必须与equals一致,如果是的话   正确实现Set接口。 (参见可比较者或比较者   对于与equals一致的精确定义。)就是这样   因为Set接口是根据equals操作定义的,   但是TreeSet实例使用它执行所有元素比较   compareTo(或compare)方法,因此两个被认为相等的元素   从该集合的角度来看,通过这种方法是相等的。该   集合的行为即使其排序不一致也是明确定义的   与...平等它只是没有遵守集合的一般合同   接口

来自Comparable javadoc

  

C类的自然排序据说是一致的   当且仅当e1.compareTo(e2)== 0具有相同的布尔值时才等于   作为类C的每个e1和e2的e1.equals(e2)。注意null不是   任何类的实例,e.compareTo(null)应抛出一个   即使e.equals(null)返回false,也会出现NullPointerException。

来自Collection javadoc

  

boolean contains(Object o)

     

如果此集合包含,则返回true   指定的元素。更正式地说,当且仅当这样时,返回true   集合包含至少一个元素e,使得(o == null?   e == null:o.equals(e))。

因此,根据规范,不能有任何类实现Collection<E>接口,完全依赖于某些外部Comparator样式对象来插入对象。所有集合都应使用equals类的Object方法来验证对象是否已插入。

答案 3 :(得分:0)

绝对没有类似的东西,hashcode()equals()定义了对象的属性,不应该更改。它们定义了使对象彼此相等的原因,并且这不应该从一个集合到另一个集合。做你正在谈论的唯一方法是子类化对象并编写一个新的hashcode()equals(),如果子类有一个应该添加的定义变量,那么这才有意义。除了超类“hashcode()equals()之外。我知道这可能不是你的目标,但我希望这会有所帮助。如果你想要更多地解释你的理由,那么如果存在一个更好的解决方案可能会有所帮助。