【发布时间】:2016-12-14 18:11:38
【问题描述】:
基于哈希表的 dict/map 结构提供O(1) 查找时间。然而,我一直看到,在 Elixir 中,找到匹配的函数头比在地图中查找内容要快。
例如,Elixir 的 String.Unicode compiles a list of unicode characters into many function heads,因此通过查找 upcase 的函数头来回答“é 的大写版本是什么”。
我不知道为什么这比在地图中查找“é”的单个 upcase 函数头更快或更节省内存。
同样,在“Metaprogramming Elixir”中展示如何构建 I18n 库时,Chris McCord 为每个翻译键指定了自己的函数头,并说:
“通过为每个翻译映射生成函数头,我们再次让虚拟机接管以进行快速查找。”
Elixir 中的映射不提供 O(1) 查找吗? 是在 O(1) 中查找匹配函数吗?为什么选择为许多函数头编译一个静态列表而不是仅仅将它存储在一个映射中?
【问题讨论】:
-
请记住,复杂性分析不是速度。一个 O(1) 函数的运行速度可能比另一个快十倍。无论如何,散列不是 O(1)。在某些情况下它可能会接近或摊销到 O(1)(概率为 O(1)),但碰撞总是会将其推向 O(n)。
-
@paxdiablo 我理解复杂性!= 速度,这是一个很好的观点。至于碰撞,我看不出它们是如何向 O(N) 推进的。哈希表将限制每个桶的密钥数量 - 例如,最多 10 个。所以在桶中查找永远不会超过 10 次检查,因此 O(1),对吗?使用一个好的散列算法,重新散列的需要应该越来越少 - 例如,每次我们重新散列时,我们必须做两倍于上次的工作,但我们需要花费两倍的时间才能这样做,所以它摊销到 O (1)。如果不知何故新的密钥一直在同一个桶中,这是一个糟糕的哈希算法,对吧?
-
@Nathan,如果允许您限制数据,所有算法都变为 O(1)。复杂性分析适用于任意数据。您可以通过例如使用散列的散列将问题推到更远的地方,但是,没有数据限制,问题将永远存在。
-
@paxdiablo :) 是的,但我相当确定限制每个桶的键数量对于拥有表获得 O(1) 性能是必要的。我不是说限制散列中的项目数量,只是当桶太满时我们重新散列所有内容。我已经实现了一个散列,并在nathanmlong.com/2015/10/reimplementing-rubys-hash 上写过它——也许可以跳到“我们实现 O(1) 了吗?”我想也许我们以某种方式相互误解了——你听起来好像你知道你在说什么,我很确定我也知道。 :)
标签: elixir