- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我很难理解 java-9 ImmutableCollections.SetN
的实现细节;具体为什么需要将内部数组增加两次。
假设你这样做:
Set.of(1,2,3,4) // 4 elements, but internal array is 8
更准确地说,我完全理解为什么在 HashMap
的情况下要这样做(双重扩展) - 你永远(几乎)不希望 load_factor
是一个。 !=1
值可以缩短搜索时间,因为条目可以更好地分散到存储桶中。
但是如果是不可变集 - 我真的无法判断。特别是选择内部数组索引的方式。
让我提供一些细节。首先索引是如何搜索的:
int idx = Math.floorMod(pe.hashCode() ^ SALT, elements.length);
pe
是我们放入集合中的实际值。 SALT
只是在启动时生成的 32 位,每个 JVM
一次(如果您愿意,这就是实际的随机化)。我们的示例中的 elements.length
为 8
(4 个元素,但这里是 8 - 大小加倍)。
这个表达式就像一个负安全模运算。请注意,当选择存储桶时,HashMap
中会执行相同的逻辑操作,例如 ((n - 1) & hash
)。
因此,如果我们的情况下 elements.length 为 8
,则此表达式将返回任何小于 8 (0, 1, 2, 3, 4, 5, 6, 7)
.
现在该方法的其余部分:
while (true) {
E ee = elements[idx];
if (ee == null) {
return -idx - 1;
} else if (pe.equals(ee)) {
return idx;
} else if (++idx == elements.length) {
idx = 0;
}
}
让我们分解一下:
if (ee == null) {
return -idx - 1;
这很好,这意味着数组中的当前槽为空 - 我们可以将我们的值放在那里。
} else if (pe.equals(ee)) {
return idx;
这很糟糕 - 插槽已被占用,并且已经就位的条目等于我们想要放置的条目。 Set
不能有重复的元素 - 因此稍后会抛出异常。
else if (++idx == elements.length) {
idx = 0;
}
这意味着这个槽被占用(哈希冲突),但是元素不相等。在 HashMap
中,此条目将被放入与 LinkedNode
或 TreeNode
相同的存储桶中 - 但此处情况并非如此。
因此,index
会递增,并尝试下一个位置(需要注意的是,当它到达最后一个位置时,它会以循环方式移动)。
问题是:如果在搜索索引时没有做任何太奇特的事情(除非我遗漏了一些东西),为什么需要一个两倍大的数组?或者为什么函数不这样写:
int idx = Math.floorMod(pe.hashCode() ^ SALT, input.length);
// notice the diff elements.length (8) and not input.length (4)
最佳答案
SetN
的当前实现是一个相当简单的封闭散列方案,与 HashMap
使用的单独链接方法相反。 (“封闭散列”也容易被称为“open addressing”。)在封闭散列方案中,元素存储在表本身中,而不是存储在从每个表槽链接的元素列表或树中,这是单独的链接。
这意味着如果两个不同的元素散列到同一个表槽,则需要通过为其中一个元素找到另一个槽来解决此冲突。当前的 SetN 实现使用线性探测解决了这个问题,其中按顺序检查表槽(在末尾环绕),直到找到空槽。
如果您想存储 N 个元素,它们肯定适合大小为 N 的表。您始终可以找到集合中的任何元素,尽管您可能必须探测几个(或许多)连续的表槽才能找到它,因为会发生很多冲突。但是,如果在集合中探测到不是成员的对象,则线性探测必须检查每个表槽,然后才能确定该对象不是成员。对于完整的表,大多数探测操作将降级为 O(N) 时间,而大多数基于哈希的方法的目标是操作时间为 O(1) 时间。
因此,我们进行了类时空权衡。如果我们把 table 做得更大, table 上就会出现一些空槽。存储元素时,应该减少碰撞,线性探测会更快地找到空槽。彼此相邻的满槽簇将会更小。对非成员的探测将进行得更快,因为他们在线性探测时更有可能更快地遇到空槽——可能在根本不需要重新探测之后。
在实现过程中,我们使用不同的扩展因子运行了一系列基准测试。 (我在代码中使用了术语EXPAND_FACTOR,而大多数文献使用负载因子。原因是扩展因子是负载因子的倒数,如中所使用的>HashMap
,并且使用“负载因子”来表示这两种含义会令人困惑。)当扩展因子接近 1.0 时,探针性能非常慢,正如预期的那样。随着膨胀系数的增加,它得到了显着改善。当达到 3.0 或 4.0 时,改进确实趋于平缓。我们选择 2.0,因为与 HashSet
相比,它获得了大部分性能改进(接近 O(1) 时间),同时提供了良好的空间节省。 (抱歉,我们尚未在任何地方发布这些基准数据。)
当然,所有这些都是实现细节,并且随着我们找到更好的方法来优化系统,可能会从一个版本到下一个版本发生变化。我确信有一些方法可以改进当前的实现。 (幸运的是,当我们这样做时,我们不必担心 preserving iteration order。)
关于开放寻址和性能与负载因子的权衡的很好的讨论可以在第 3.4 节中找到
Sedgewick, Robert and Kevin Wayne. Algorithms, Fourth Edition. Addison-Wesley, 2011.
在线图书网站是 here但请注意,打印版有更多详细信息。
关于java - ImmutableCollections SetN 实现细节,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59627308/
前言 本文主要介绍了关于MySQL主键为0与主键自排约束的关系,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧。 开始不设置主键表的设计如下: 如果id的位置有好几个0
我已经阅读了一些关于将消息从一个线程冒泡到所有其他线程以正常退出的正确方法的来源(每个线程都执行它自己的退出例程)。其中,我喜欢全局原子 bool 值的想法,它可以从任何线程进行标记,所有其他线程检查
本文深入探讨Go语言中的流程控制语法,包括基本的 if-else 条件分支、 for 循环、 switch-case 多条件分支,以及与特定数据类型相关的流程控制,如 for-r
我是 MVC 和 XCode 的新手,在将我对 MVC 的概念理解转化为设计和实现具体类时遇到了困难。我希望就如何构建 Controller 和 View 以获得预期的 UI 获得一些建议。这是针对
如果我尝试在 View 中打开 DeatilFragement,我的应用程序崩溃并收到以下错误: Caused by: java.lang.IllegalStateException: Require
我正在尝试构建我的 iOS 应用程序的界面。一遍又一遍地开始新项目我仍然遇到细节 View 控件的问题(见图)。 在这里我得到了截图: 详细 View 显示当用户触摸 UITableView 行时。您
我在与我正在处理的项目的类(class)中遇到问题。该类是一个接受标签和值的 GUI 组件。这里的想法是,用户可以指定一个标签,然后从任何地方链接一个值(更具体地说,该值的 ToString 方法),
嗯.. 我在我的应用程序中设置了表格 View - 详细 View 。 主视图使用常规代码将数据传递给详细 View - (void)tableView:(UITableView *)tableVie
我有 celery 任务,队列中有 100 个输入数据,需要使用 5 个 worker 来执行。 如何获取哪个工作人员正在执行哪个输入? 每个 worker 执行了多少输入及其状态? 如果任何任务失败
我有一个 .net github 项目,它基本上是一个 Web API 的包装器。在测试项目中,我使用 API key 调用 API。我需要将此 key 保密,如何在 Visual Studio 项目
我遇到一个问题,从 Ag-Grid 导出网格只会导出主网格的详细信息,而不会导出子网格。这是一个显示问题的 plunkr: https://next.plnkr.co/edit/jVcvWDJ1NKP
我在详细 View 中有一个不会消失的额外空间。该 View 来自 NavigationLink,但我已经尝试过使用或不使用 NavigationView。我试图包装它用 NavigationView
几天来,我一直在关注猫效应和 IO。我觉得我对这种效果有一些误解,或者只是我错过了它的重点。 首先——如果IO可以替代Scala的Future,我们如何创建异步IO任务?使用 IO.shift ?使用
如何将标高添加到主视图/详细 View 的详细信息 Pane 中,以在其下方提供阴影,同时定位为部分覆盖工具栏(如下面的底部图片)?我尝试使用 android:elevation="4dp" 但这对我
我试图在我的 UISplitViewController 的细节 View 上设置一个阴影,我希望在 iOS 6 中的主 View 上可见。 在我的细节 View Controller 中: sel
我正在阅读 std::basic_string::reserve(size_type res_arg=0) 上的标准.它是这样说的: void reserve(size_type res_arg=0)
Boost 文档说 Starting with Boost release 1.53, shared_ptr can be used to hold a pointer to a dynamicall
我用 OpenGL 编写了一个简单的 24 位位图加载器。我打开一个位图文件并读取它的像素,然后从中创建一个 RGB 像素数据数组,然后将其传递给 glDrawPixels()。 问题:我需要使图像的
for x in ...循环 就是把每个元素代入变量x,然后执行缩进块的语句。 range()函数,可以生成一个整数序列,再通过list()函数可以转换为list。 比如我们想计算1-10的整数
场景 我有一个 DevExpress XtraGrid。 显示的数据采用主/详细信息格式,点击行开头的“+”可展开该主行的详细信息。 我通过将网格数据源绑定(bind)到包含自己的字典属性(以保存详细
我是一名优秀的程序员,十分优秀!