散列如何具有 o(1) 搜索时间? [复制]

Posted

技术标签:

【中文标题】散列如何具有 o(1) 搜索时间? [复制]【英文标题】:How does hashing have an o(1) search time? [duplicate] 【发布时间】:2011-05-20 19:07:37 【问题描述】:

当我们使用HashTable 存储数据时,据说搜索需要o(1) 时间。我很困惑,谁能解释一下?

【问题讨论】:

hashTable 中的查找成本是一个摊销常数 O(1)——大多数时候我们只做恒定的工作,但偶尔(有冲突的地方)我们会做一些直接比较,这可以再次成为二分或线性搜索。 【参考方案1】:

如果哈希表中没有冲突,则搜索需要 O(1) 时间,因此 sya 认为在哈希表中搜索需要 O(1) 或恒定时间是不正确的。

See how Hashtable works on MSDN?

编辑

mgiuca 很好地解释了它,我只是添加了一种称为链接的碰撞避免技术。

在这种技术中,我们在每个位置维护一个值的链接列表,因此当您有碰撞时,您的值将被添加到该位置的链接列表中,因此当您搜索值时,您可能需要搜索整个链接列表中的值,这样在这种情况下搜索将不是 O(1) 操作。

【讨论】:

【参考方案2】:

嗯,这是一个的谎言——它可能需要更长的时间,但通常不会。

基本上,哈希表是一个包含所有要搜索的键的数组。数组中每个键的位置由 散列函数 确定,该函数可以是始终将相同输入映射到相同输出的任何函数。我们假设散列函数是O(1)。

所以当我们在哈希表中插入一些东西时,我们使用哈希函数(我们称之为h)来找到放置它的位置,并把它放在那里。现在我们插入另一个东西,散列和存储。还有一个。每次我们插入数据,都需要 O(1) 的时间来插入(因为哈希函数是 O(1)。

查找数据是一样的。如果我们想找到一个值,x,我们只需要找出h(x),它告诉我们x在哪里哈希表。所以我们也可以在 O(1) 中查找任何哈希值。

现在说谎:上面是一个非常好的理论,但有一个问题:如果我们插入数据并且数组的那个位置已经有东西怎么办?没有什么可以保证散列函数不会为两个不同的输入产生相同的输出(除非你有一个perfect hash function,但这些很难产生)。因此,当我们插入时,我们需要采取以下两种策略之一:

在数组的每个位置存储多个值(例如,每个数组槽都有一个链表)。现在,当您进行查找时,到达数组中的正确位置仍然是 O(1),但可能是线性搜索(希望是短的)链表。这称为“分离链接”。 如果您发现某些东西已经存在,请再次散列并找到另一个位置。重复直到你找到一个空的地方,然后把它放在那里。查找过程可以遵循相同的规则来查找数据。现在到达第一个位置仍然是 O(1),但是有一个潜在的(希望是短的)线性搜索在桌子周围反弹,直到找到你想要的数据。这称为“开放寻址”。

基本上,这两种方法仍然大部分 O(1),但具有希望短的线性序列。对于大多数目的,我们可以假设它是 O(1)。如果哈希表太满,那些线性搜索会变得越来越长,然后是时候“重新哈希”了,这意味着创建一个更大的新哈希表并将所有数据重新插入其中.

【讨论】:

非常感谢您的解释.. +1 :为了更好地解释它,还有其他技术也可以避免冲突,例如“字典基本上使用链式,双散列等。” @user531802 没问题。如果您对这个答案感到满意,您是否可以勾选“接受的答案”复选框? 哇 --- 所以哈希是数组 index,而不是线性搜索索引? 对此进行很好的解释-the hash table is getting too full, those linear searches can become longer and longer, and then it is time to "re-hash" which means to create a new hash table of a much bigger size检查-***.com/questions/2369467/…

以上是关于散列如何具有 o(1) 搜索时间? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何使用修改后的 Rabin-Karp 为字母分配数字以进行字谜搜索

哈希结构介绍及实现(线性探测)——闭散列解决哈希冲突

具有 O(1) 查找速度的区间搜索算法

绳索的有效重新散列

如何散列和检查具有循环引用的对象的相等性

具有 32 位整数的低冲突率的快速字符串散列算法 [关闭]