我想创建一个数据结构或集合,在添加,删除和计算no时会有O(1)的复杂性。元素。我该怎么开始?
我想到了一个解决方案:我将使用Hashtable并且对于插入的每个键/值对,我将只有一个哈希码,即:我的哈希码算法每次都会生成一个唯一的哈希值,所以存储该值的索引将是唯一的(即没有冲突)。
这会给我O(1)复杂性吗?
答案 0 :(得分:3)
是的,这将有效,但正如您所提到的,您的散列函数需要100%唯一。任何重复都将导致您必须使用某种冲突解决方案。我建议使用线性链接。
编辑:Hashmap.size()允许O(1)访问
编辑2:响应Larry造成的混乱= P
是,Hashing是O(k),其中k是键长。每个人都可以就此达成一致。但是,如果您没有完美的哈希,那么您根本无法获得O(1)时间。您的主张是您不需要唯一性来实现O(1)删除特定元素。我保证你错了。
考虑一个最糟糕的情况:每个元素哈希都是同一个东西。你最终得到一个链表,众所周知,没有O(1)删除。我希望,正如你所提到的,没有人会愚蠢地做出这样的哈希。
重点是,散列的唯一性是O(1)运行时的先决条件。
尽管如此,从技术上讲,它不是O(1)Big O效率。只有使用摊销分析才能在最坏的情况下实现恒定的时间效率。正如维基百科关于摊销分析的文章所述
基本思路是,最坏情况下的操作可以改变状态,使最坏情况不会再发生很长时间,从而“摊销”其成本。
这是指在某些负载因子下调整哈希表的大小(改变数据结构状态)的想法可以确保更小的冲突机会等。
我希望这能解决所有问题。
答案 1 :(得分:2)
添加,删除和大小(如果它是单独跟踪,使用简单的计数器)可以由链表提供。除非您需要删除特定项目。您应该更加具体地了解您的要求。
答案 2 :(得分:1)
即使你确切地知道被散列的东西的空间,做一个完全没有冲突的哈希函数也是非常棘手的,而且一般来说这是不可能的。它还很大程度上取决于您正在散列的数组的大小。也就是说,你需要确切地知道你正在做些什么才能做到这一点。
但是如果您放松一点,以便相同的哈希码不会暗示相等 1 ,那么您可以将现有的Java HashMap
框架用于所有其他部分。您需要做的就是在您的密钥类中插入您自己的hashCode()
实现,这是Java一直支持的。并确保你也正确定义了平等。那时,你已经完成了各种操作并不比O(1)贵得多,特别是如果你对容量和负载系数有一个很好的初步估计。
1 当然,平等必须意味着相等的哈希码。
答案 3 :(得分:1)
即使您的哈希码是唯一的,也不保证无碰撞收集。这是因为您的哈希映射不是无限大小。哈希码必须减少到哈希映射中的桶数,在减少之后,您仍然可以获得冲突。
e.g。假设我有三个对象A(哈希:2),B(哈希:18),C(哈希:66)所有唯一。 假设您将它们放在容量为16(默认值)的HashMap中。如果它们在减少哈希码后被映射到%16的桶(实际上比这更复杂)我们现在有A(哈希:2%16 = 2),B(哈希:18%16 = 2),C(哈希:66%16 = 2)
除非你需要线程安全,否则HashMap可能比Hashtable更快。 (在这种情况下,我建议你使用CopncurrentHashMap) 恕我直言,Hashtable已有12年的遗产收藏,我建议你只在必要的时候使用它。
答案 4 :(得分:0)
链接列表无法提供哪些功能?
答案 5 :(得分:0)
令人惊讶的是,如果您事先知道所有要放入集合中的密钥,那么您的想法就会奏效。我们的想法是生成一个special hash function,它将每个键映射到(1, n)
范围内的唯一值。然后我们的“哈希表”只是一个简单的数组(+一个整数来缓存元素的数量)
实现这一点并非无足轻重,但它也不是火箭科学。我将把它留给Steve Hanov来解释这些细节,因为他提供了比我更好的解释。
答案 6 :(得分:-3)
这很简单。只需使用哈希映射。你不需要做任何特别的事情。 Hashmap本身是O(1)用于插入,删除,计算元素数量。
即使键不是唯一的,只要Hashmap的大小自动扩展(如果集合太大(大多数实现将自动为您执行),算法仍然是O(1)。
因此,只需根据给定的文档使用哈希映射,一切都会好的。不要想任何更复杂的事情,这只会浪费时间。
使用哈希确实不可能避免冲突..如果可能的话,它基本上只是一个数组或映射到数组,而不是哈希。但是没有必要避免碰撞,它仍然是O(1)与碰撞。