4

人们说它需要摊销 O(1) 才能放入哈希表。因此,放置 n 个元素必须是 O(n)。然而,对于大 n 而言,情况并非如此,因为正如一位回答者所说,“满足预期摊销 O(1) 所需的只是扩展表并在发生冲突时使用新的随机散列函数重新散列所有内容。”

那么:将 n 个元素插入哈希表的平均运行时间是多少?我意识到这可能取决于实现,所以请提及您正在谈论的实现类型。

例如,如果有 (log n) 个等距碰撞,并且每次碰撞都需要 O(k) 来解决,其中 k 是哈希表的当前大小,那么您将具有以下递归关系:

T(n) = T(n/2) + n/2 + n/2

(也就是说,你花时间插入 n/2 个元素,然后你有一个冲突,需要 n/2 来解决,然后你在没有冲突的情况下进行剩余的 n/2 插入)。这仍然是 O(n),所以是的。但这合理吗?

4

4 回答 4

5

这完全取决于您的重新散列效率有多低。具体来说,如果您可以正确估计第二次哈希表的预期大小,您的运行时间仍接近 O(n)。实际上,在确定预期顺序之前,您必须指定重新哈希大小计算的低效程度。

于 2009-05-05T19:24:52.290 回答
5

人们说它需要摊销 O(1) 才能放入哈希表。

从理论的角度来看,预计摊销 O(1)。

哈希表本质上是一种随机数据结构,就像快速排序是一种随机算法一样。您需要生成具有一定随机性的散列函数,否则存在不是 O(1) 的病态输入。

您可以使用动态完美散列实现预期的摊销 O(1) :

我最初发布的幼稚想法是在每次碰撞时使用新的随机散列函数重新散列。(另见完美哈希函数)问题在于,这需要 O(n^2) 空间,来自生日悖论。

解决方案是有两个哈希表,第二个表用于冲突;通过重建它来解决第二个表上的冲突。该表将有 O(\sqrt{n}) 个元素,因此会增长到 O(n) 个大小。

在实践中,您通常只使用固定的哈希函数,因为您可以假设(或不在乎)您的输入是病态的,就像您经常快速排序而不预先随机化输入一样。

于 2009-05-05T21:16:44.253 回答
1

所有 O(1) 的意思是操作是在恒定时间内执行的,它依赖于数据结构中的元素数量。

简而言之,这意味着无论您的数据结构有多大,您都必须支付相同的成本。

实际上,这意味着当您不必存储大量数据时,简单的数据结构(例如树)通常更有效。根据我的经验,我发现树的速度更快,最多可达 1k 个元素(32 位整数),然后哈希表接管。但像往常一样YMMW。

于 2009-05-05T22:31:38.050 回答
0

为什么不在您的系统上运行一些测试?也许如果您发布源代码,我们可以返回并在我们的系统上对其进行测试,我们可以将其真正塑造成一个非常有用的讨论。

决定算法实际花费多少时间的不是实现,而是环境。但是,您可以查看是否有任何基准测试样本可用。我发布结果的问题将毫无用处,因为人们不知道我的系统上还运行着什么,现在有多少 RAM 可用等等。你只能有一个广泛的想法。这和大 O 给你的一样好。

于 2009-05-05T19:25:36.627 回答