golang中map的Big O表现如何?

Posted

技术标签:

【中文标题】golang中map的Big O表现如何?【英文标题】:What is the Big O performance of maps in golang? 【发布时间】:2015-06-23 00:48:45 【问题描述】:

"Map types" section of the go language specification 描述了映射类型的接口和一般用法,"Go maps in action" post on The Go Blog 随便提到了哈希表和“快速查找、添加和删除”。

current runtime/hashmap.go source code 将其实现描述为哈希表(通常摊销 O(1));但是,我在语言规范或其他材料中看不到任何性能特征(例如 Big O 性能)的保证。

go 语言是否为地图类型做出任何性能 保证(例如恒定时间插入/查找/删除?)或仅接口 保证? (与 接口实现 明显分开的 Java 语言相比。)

【问题讨论】:

相关,看看这个页面:Issue 3885: profile and tune map code (old link) 哈希不是 O(1),例如。对于字符串。 【参考方案1】:

语言参考并未明确保证地图的性能。有一个隐含的期望,即 map 的性能与您期望的哈希表一样。我看不出性能保证如何避免模糊指定或不准确。

Big-O 复杂性是描述地图运行时间的糟糕方式:实际上,实际时钟时间是相关的,而复杂性则不相关。从理论上讲,带有来自有限域(例如整数)的键的映射在空间和时间上是微不足道的 O(1),而带有无限域(例如字符串)的键的映射需要散列和相等性测试的细节包括在成本中,这使得插入和查找的最佳情况平均为 O(N log N)(因为键的大小平均必须至少为 O(log N) 才能构建具有 N 个条目的哈希表。除非您在规范将是不准确的,并且正确的好处显然不值得。

要提供关于实际运行时间而不是复杂性的保证也很困难:目标机器范围很广,以及缓存和垃圾收集的混杂问题。

【讨论】:

【参考方案2】:

准确地说,哈希表的性能是 O(1 + n/k) 来解决冲突,其中 n/k 指的是负载因子。 Go 规范声明地图在键数量上是非限制性的。因此,他们需要动态调整大小并部分重新散列,以在增长或缩小时保持负载因子。这意味着在恒定大小的映射中查找可以轻松实现接近 O(1),但在理论上甚至不能保证大量插入或删除。此类操作需要重新分配、部分重新散列和可能的垃圾收集,以保持负载因子和合理的内存使用。

【讨论】:

感谢您提供详细信息。我想我正在寻找的是关于甚至一般特征的书面保证,例如各种操作的对数时间与恒定时间。 正如你在源代码中看到的 // 当哈希表增长时,我们分配一个新数组 // 两倍大的桶 所以在我看来,当在新地图中顺序插入 N 个项目时,您可以假设对数时间。然后在 O(1) 附近进行查找 当然,不要忘记您可以向make 提供尺寸提示,以便在您知道尺寸(或近似尺寸)时跳过部分/所有这些重新分配。 【参考方案3】:

据我所知,Go Programming Language Specification 不对地图类型做出任何性能保证。 Hash tables 插入、查找和删除数据的时间一般为 O(1);我们可以假设 Go 的地图也是如此。

如果您担心地图性能,您可以随时benchmark 您的代码在不同的负载上决定是使用 Go 的地图还是其他一些数据结构。

【讨论】:

+1,挑剔:amortized O(1) 感谢您的回答!我想我想看看我们是否只能假设我们将得到摊销的O(1) 地图操作性能,或者是否有(或将会有)任何书面保证 i>.

以上是关于golang中map的Big O表现如何?的主要内容,如果未能解决你的问题,请参考以下文章

在一个 IP 上托管多个 Golang 站点并根据域请求提供服务?

Golang高效地拷贝big.Int

Golang 高效的原地数组去重

golang hashmap的使用及实现

Big-O 表示法和编码

怎么计算算法复杂度 big O