繁体   English   中英

如何有效地为Java中的单链表节点实现hashCode()?

[英]How to efficiently implement hashCode() for a singly linked list node in Java?

Eclipse通过以下方式为单链表的Node类实现hashCode()函数:

class Node{
    int val;
    Node next;

    public Node(int val){
        this.val = val;
        next = null;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((next == null) ? 0 : next.hashCode());
        result = prime * result + val;
        return result;
    }
}

现在,节点的hashCode()依赖于它后面的节点的哈希码。

因此,每次调用hashCode()都会在链表长度中占用分摊的线性时间。 因此,使用HashSet<Node>将变得不可行。

解决这个问题的一种方法是将hashCode的值缓存在一个变量中(称之为hash),这样它只能被计算一次。 但即使在这种情况下,一旦任何节点的val改变,哈希将变为无效。 同样,需要线性时间来修改当前节点之后的节点的hashCode

那么为这样的链表Node实现散列的一些好方法是什么?

我在阅读你的问题时首先想到的是: LinkedList做了什么? 深入研究源代码,我们看到内部LinkedList.Node类( 链接到源 )上没有定义hashCode()equals() )。

为什么这有意义? 嗯,节点通常是内部数据结构,只对列表本身可见。 它们不会被放置到集合或任何其他需要比较相等和哈希码的数据结构中。 没有外部代码可以访问它们。

你在问题中说:

因此,使用HashSet<Node>将变得不可行。

但我认为您不需要将节点放在这样的数据结构中。 根据定义,您的节点将相互链接,并且不需要其他类来促进该关系。 除非你打算在列表之外公开这个类(这是不必要的),否则它们永远不会以HashSet结尾。

我建议你遵循LinkedList.Node模型,避免在你的节点上创建这些方法。 外部列表可以基于存储在节点中的值(但不是节点本身)的哈希码和相等性,这是LinkedList工作方式 - 请参阅AbstractList链接到源 )。

源链接指向OpenJDK源,但在这种情况下,它们与Oracle JDK提供的源相同

你必须问自己什么样的哈希值对你来说是有价值的。 唯一的限制是确保具有相同顺序的相同编号的另一个列表具有相同的散列。 这是通过使用一个数字以及使用第一个以及限制5个数字来实现的。 多少数字对您有意义取决于数据的结构。 例如,如果您始终存储从1开始的连续,升序数字,并且差异仅是长度,则难以优化。 如果它在整个int范围内完全随机,则第一个数字将很好地完成工作。 通过衡量,我会说,有多少数字可以为您提供最佳比例。

最后你需要的是碰撞(放在同一个桶中的物体)和计算时间之间的良好比例。 生成的实现通常试图最大化计算时间,为人类开发人员提供了很大的改进空间。 ;-)

关于包含值的更改:java.util.HashSet(分别是它所拥有的HashMap)将在你自己的哈希值上计算,并缓存它。 因此,如果在HashSet中包含的对象一旦改变到其哈希值发生变化就无法再次找到。

暂无
暂无

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

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