![]() |
1
51
这里有两个变量m和n,其中m是输入的长度,n是散列中的项数。 o(1)查找性能声明至少作出了两个假设:
如果对象是可变大小的,并且相等检查要求查看所有位,那么性能将变为o(m)。然而,哈希函数不必是o(m)-它可以是o(1)。与加密散列不同,字典中使用的散列函数不必为了计算散列而查看输入中的每个位。实现可以只查看固定数量的位。 对于足够多的项,项的数量将大于可能的散列的数量,然后您将获得导致性能高于o(1)的冲突,例如,对于简单的链表遍历(或o(n*m),如果两个假设都为假)。 实际上,虽然o(1)声明在技术上是错误的,但是 大约 适用于许多现实世界的情况,尤其是上述假设成立的情况。 |
![]() |
2
19
什么?散列单个元素需要恒定的时间。为什么会是别的?如果你要插入
不一定。bucket不一定是列表或数组,它们可以是任何容器类型,比如平衡的bst。
哈希表的取舍当然是空间复杂性。你在用空间换取时间,这似乎是计算机科学中的常见情况。
您提到在其他注释中使用字符串作为键。你担心计算一个字符串的散列所需的时间,因为它由几个字符组成?正如其他人再次指出的那样,您不必查看所有的字符来计算散列,尽管如果这样做,它可能会产生更好的散列。在这种情况下,如果平均有
|
![]() |
3
4
哈希是固定大小的-查找适当的哈希桶是一个固定成本的操作。这意味着它是o(1)。 计算哈希不一定是一个特别昂贵的操作-我们这里不讨论加密哈希函数。但那是顺便说的。哈希函数计算本身不依赖于数字 n 元素;虽然它可能取决于元素中数据的大小,但这不是 n 是指。所以散列的计算不依赖于 n 也是o(1)。 |
![]() |
4
2
只有当表中只有固定数量的键并且进行了一些其他假设时,散列才是o(1)。但在这种情况下,它有优势。 如果密钥有N位表示,则哈希函数可以使用1、2、…N个。考虑使用1位的哈希函数。评价是肯定的。但你只是把密钥空间分割成2个。因此,您将多达2^(n-1)个键映射到同一个bin中。使用bst search这需要n-1个步骤来定位一个特定的密钥(如果几乎满了)。 您可以对此进行扩展,以查看如果哈希函数使用k位,则bin大小为2^(n-k)。 因此,k位散列函数==>不超过2^k个有效的bin==>每个bin最多2^(n-k)个n位键==>(n-k)个步骤(bst)来解决冲突。实际上,大多数散列函数的“效率”要低得多,并且需要/使用超过k位才能生成2^k个容器。所以即使这样也很乐观。 您可以这样查看它——您需要~n个步骤才能在最坏的情况下唯一地区分一对n位的密钥。真的没有办法绕过这个信息理论的限制,不管哈希表是不是。 但是,这不是如何/何时使用哈希表! 复杂性分析假设对于n位键,表中可能有o(2^n)个键(例如,所有可能键的1/4)。但大多数情况下,如果不是所有的时候,我们使用哈希表,我们只有一个固定数量的n位键在表中。如果只希望表中的键数恒定,比如说c是最大值,那么可以形成一个o(c)bin的哈希表,以确保预期的恒定冲突(具有良好的哈希函数);以及使用键中n位的~logc的哈希函数。那么每个查询都是o(logc)=o(1)。这就是人们声称“哈希表访问是o(1)”的方式。/ 这里有几个陷阱——首先,说你不需要所有的比特可能只是一个计费技巧。首先,不能真正地将键值传递给散列函数,因为这将移动内存中的n位,即o(n)。所以你需要做一个引用传递。但是您仍然需要将它存储在已经是o(n)操作的某个地方;您只是不将它计入散列;您的整个计算任务无法避免这一点。其次,进行散列,找到bin,并找到1个以上的键;您的开销取决于您的解析方法——如果您执行基于比较(bst或list)的操作,您将执行o(n)操作(回调键为n位);如果您执行第二个散列,那么,如果第二个散列发生冲突,您将遇到相同的问题。所以O(1)不是100%保证的,除非你没有冲突(你可以通过一张比钥匙有更多箱子的桌子来提高机会,但仍然如此)。 在这种情况下,考虑另一种选择,例如bst。有c个键,所以平衡的bst将是o(logc)深度,所以搜索需要o(logc)步骤。然而,在这种情况下的比较将是O(N)操作…因此,在这种情况下,散列似乎是一个更好的选择。 |
![]() |
5
0
有两种设置可以让您 O(1) 最坏的时候。
抄袭 here |
![]() |
6
0
根据这里的讨论,如果x是bin表中元素的上限,那么一个更好的答案是o(log(x)),假设一个有效的bin查找实现。 |
![]() |
7
0
tl;dr:哈希表保证
免责声明:
我没有正式证明哈希表是
我在其他的答案和评论中看到了关于这个话题令人惊讶的大量混乱,我将在这个漫长的答案中尝试纠正其中的一些。 最坏情况的推理有不同类型的最坏情况分析。到目前为止,大多数答案都是这样分析的 不是 最坏的情况,但是 平均情况 [ 2 ]。 平均情况 分析往往更实际。也许你的算法有一个坏的最坏情况输入,但实际上对所有其他可能的输入都很有效。底线是你的运行时间 取决于数据集 你继续跑。
考虑下面的伪代码
正如其他答案所指出的,这是平均值
(1)将哈希表算法交给对手。 (2)对手想学就学,想学就准备。
(3)最后对手给了你一个大小输入
问题是:对手输入的哈希表有多快?
在步骤(1)中,对手知道你的哈希函数;在步骤(2)中,对手可以创建
为什么散列是o(1)?
在上一次的挑战中,我们失败的是对手非常了解我们的散列函数,并且可以利用这些知识来设计最差的输入。
如果我们不总是使用一个固定的散列函数,而是有一组散列函数,
首先假设我们的哈希表还包含一个种子
如果我们再尝试一次挑战:从步骤(1)开始,对手可以知道我们的所有哈希函数
对对手来说,这是一个严肃的赌注,他精心制作的名单在下面相撞
将此结果与以前的算法(对手总是赢得挑战)进行对比。在这里手写一点,但是自从
大多数时候
对手会失败,这对于对手可以尝试的所有策略都是正确的,尽管最坏的情况是
同样,这不是一个正式的证据。从这个预期的最坏情况分析中我们得到的保证是我们的运行时间现在是 独立于任何特定输入 . 这是一个真正随机的保证,而不是一般的案例分析,我们显示一个有动机的对手可以很容易地制造出不好的输入。 |
![]() |
S. Jacson · 任意两台发电机的速度差(内置功能) 2 年前 |
![]() |
Sadeq Dousti · 相当于“嵌套删除”的执行性能SQL查询 2 年前 |
![]() |
Prince · 复制大型文件需要更多时间 2 年前 |
![]() |
Sagar · 为什么在循环之外声明变量会更快? 2 年前 |
![]() |
seco · 如何在不挂起页面的情况下加载JS 2 年前 |