无论我使用何种语言,我总是希望使用等效的hashmap。但是,我正在接受一些练习面试的问题,并询问对此有何限制?
我能想到的唯一原因是有限的主内存,但那不仅限于散列图,还包括ArrayLists等等。
答案 0 :(得分:10)
O(1)
,但随着表的增长,偶尔会注意到线性延迟O(n)
。 (这种行为特征导致一些人建议在默认/天真的情况下偏好哈希表上的树。)int
)。如果你有许多具有相同值的项目(任何人都为零?)那么你的哈希表将降级为精心设计的链表,性能将大幅下降。equals()
或.NET的Equals()
)来比较同一组字段用于哈希码。 (理想情况下,这意味着您添加到表中的对象是不可变的,但您也可以确保任何可变字段与哈希代码计算和equals方法无关:一个冒险的策略。通过更改哈希代码,表格将以后来检索它们时,无法找到您已添加的条目。另见:
答案 1 :(得分:3)
为正确的工作使用正确的数据结构。如果您不需要密钥访问,请不要使用Map
。
就HashMap
限制而言,我想如果项目有一个糟糕的哈希算法,它可能会受到影响,但就此而言。
答案 2 :(得分:2)
链式哈希表还继承了链表的缺点。 存储小键和值时,下一个空间开销 每个条目记录中的指针都可能很重要。额外的 缺点是遍历链表具有较差的缓存 性能,使处理器缓存无效。
答案 3 :(得分:1)
哈希地图的使用是情境化的。
如果没有选择你的哈希键,你的哈希映射的运行速度相当于列表的速度,增加了大量内存的问题。
一般来说,当您要对数据执行迭代任务时,Hashmaps是一个糟糕的选择。
答案 4 :(得分:1)
一个(非常重要的)限制是您不应将它们与具有不稳定(可变)哈希码的类型一起使用。 Here's Eric Lippert on the subject
答案 5 :(得分:1)
我能想到的两件事。一个是在迭代hashmap时无法保证排序(稳定或其他方式)。另一个是当你迭代它们时,它们有可能颠倒你的缓存。
答案 6 :(得分:0)
还有可能发生碰撞。如果对冲突避免的要求很严格,或者你的哈希空间很小,那么编写和/或执行散列函数的成本可能很高。
答案 7 :(得分:0)
它们意味着元素的顺序不会保留在HashMap中。接下来的问题是“如何解决这个问题”。答案是:使用LinkedHashMap能够以与插入顺序相同的顺序获取元素,并使用适当的比较器使用TreeMap按照您想要的任何条件控制顺序。
答案 8 :(得分:0)
哈希表的典型替代方法是二叉树。虽然哈希表通常更快,但内容没有任何有意义的顺序;使用二叉树对内容进行排序。
答案 9 :(得分:0)
Java上的hashmap的一个缺点是它没有同步。如果多个线程同时访问哈希映射,并且至少有一个线程在结构上修改了映射,则必须在外部进行同步。你必须将它包装在Collections.synchronizedMap
答案 10 :(得分:0)
我能想到的唯一原因是有限的主内存,但那不仅限于哈希图,而且还不仅限于ArrayLists等。
映射不必限于内存。
一些数据库提供persistent key-value store,例如Postgres中的 hstore 或H2数据库引擎中的MVStore。第二个使用与内存中实现相同的Java中定义的Map
接口。
key-value地图也可以分布在计算机网络中,保留地图的某些部分。有几种这样的产品。
键值存储的不同实现之间的特性有所不同,通常称为映射或字典。您提到了 HashMap ,但这只是制作地图的一种方法。有skip list映射,并且有一些映射通过引用(指针)而不是键的内容来跟踪对象,典型的哈希图也是如此。在Java中,EnumMap
在键基于Enum
子类的情况下进行了高度优化,其中项内部表示为枚举中定义的所有位置的位图,产生了非常快的执行速度占用很少的内存某些实现可能要比其他实现更高的并发性,具体取决于数据量,例如Java中的ConcurrentSkipListMap
。
某些映射可能接受或禁止键和/或值中的空值。这可能有助于或违反您的业务规则的需求。
在某些情况下,您可能希望保持键之间的排序顺序或原始插入顺序。
以下是我列出的Java 11提供的10个Map
实现的清单。您可以根据需要比较各个方面的优缺点。