Java的HashMap冲突解决方案

时间:2016-10-31 01:49:34

标签: java hashmap

从我在stackoverflow和其他网站上阅读的内容开始。 Java使用链表进行哈希冲突解决。

这将保证插入,获取和删除的最坏情况下的O(n)复杂度。

为什么Java不使用自平衡BST(如AVL,Red Black等)来保证在插入,获取和删除的最坏情况下的O(log n)复杂度?

2 个答案:

答案 0 :(得分:4)

Java 8 确实,如果链接链变得足够大。

但是,对于少量元素,它会增加大量内存和性能开销。链接列表对于非常少量的元素非常有效,这正是您在99%的情况下对散列桶的期望。另外,定义二叉树应该如何排序是非常明显的,并且当元素为Comparable时必须特殊情况,按未使用的哈希码位进行排序......它会变得多毛。

答案 1 :(得分:2)

大多数情况下,桶中的物品数量非常少;通常为零或一。在这些情况下,简单的哈希桶结构能够保证O(1);在一些次优边缘情况下,O(log n)BST可能会切断时间,但性能增益最多可忽略不计,最差时则为负。还有很大的内存开销。 Java 8确实努力检测链表何时不再是最佳并转换为BST;但是,如果频繁发生此行为,则表示哈希和HashMap使用不正确。

在阅读JDK的源代码时,有很多实现细节可用。以下是Oracle java.util.HashMap顶部的简要摘录:

/*
 * Implementation notes.
 *
 * This map usually acts as a binned (bucketed) hash table, but
 * when bins get too large, they are transformed into bins of
 * TreeNodes, each structured similarly to those in
 * java.util.TreeMap. Most methods try to use normal bins, but
 * relay to TreeNode methods when applicable (simply by checking
 * instanceof a node).  Bins of TreeNodes may be traversed and
 * used like any others, but additionally support faster lookup
 * when overpopulated. However, since the vast majority of bins in
 * normal use are not overpopulated, checking for existence of
 * tree bins may be delayed in the course of table methods.
 * [...]

看看HashMap#getNode和HashMap.Node的实现,我们可以看到每个桶都是一个非常简单的链表 - 比java.util.LinkedList简单,它实际上是一个双向链表。

根据评论,当列表增长到一定大小时,它会转换为树。很难确切地告诉HashMap.TreeNode发生了什么,因为代码不是完全自我描述的,但它似乎是一个简单的红黑BST。