按哈希值和索引存储的数据结构成员之间的区别

Distinction between a data structure's members being stored by hash value and by index

来自Picking the right data structure in Swift

Like we took a look at in “The power of sets in Swift”, one of the big advantages that sets have over arrays is that both inserts and removals can always be performed in constant (O(1)) time, since members are stored by hash value, rather than by index.

如果数据结构的成员按哈希值而不是索引存储,这意味着什么?

你其实是在问Array和Hash有什么区别map/table/set。这是计算机科学 "Data Structures" 课程的一部分,我相信您可以 google 对每个课程进行一些高级概述。强烈推荐:)

简而言之: 你可以把数组想象成一个长长的架子,里面有单元格,每个单元格都有序号(a.k.a.index):

Array: [ dog ][ cat ][ mouse ][ fox ]...
where dog is at cell #0, cat is at #1 and so on.

现在,在数组中,您可以使用单元格 index 检索对象,例如 "Give me the content of cell #1"。但是为了找出你的数组中是否有 "mouse" - 你必须遍历所有单元格。 (效率低下)

Sets (a.k.a.Hash maps) store objects using another index - "hash code",这是一种函数,可以为每个给定的对象计算一些伪唯一的数字(不详述) .所以猫和老鼠会有唯一的哈希码,现在对于 Set 来说,找出 Set 中是否有 "mouse" 是非常有效的。

数组被分配为单个大块内存,条目通过其索引访问。条目的顺序是固定的,除了它们在数组中的位置外,它们不需要有特定的标识。

其他更复杂的数据结构允许使用某种密钥存储识别和访问的对象。 (哈希表、集合、字典……)我们称它们为 "keyed collections"。有些对象有一个自然键,例如"SocialSecurityNumber" 但是如果需要一个密钥并且数据对象中没有明显的候选 field/s 怎么办?

散列是一种旨在派生 "fairly unique identity" 以与对象关联的技术。将其视为将数字映射到(任意)数据。

  • 尽管有一些 "standard hashing techniques",这仍然是一个不断发展的领域 - 涉及一些有趣的数学。
  • 散列的用途包括安全散列(检测和防止故意篡改数据)、错误检测以及 - 在这种情况下 - 键控(或散列)数据访问。
  • 非安全散列算法应该尽可能快,但速度优化可能涉及对映射要求的 "fairly unique" 部分的权衡(而安全散列是不可避免的 - 有时是故意的 -更慢更贵)
  • 散列不能(永远)保证给定的散列值对于一个对象是唯一的,因此必须注意尽量减少 "collisions" 的出现并优化它们出现时的处理方式。这本身就是一个困难的主题,当您认为数据必须被视为 "arbitrary" - 要么看起来是随机的,要么包含 sequences/patterns and/or 重复。

话虽如此,假设我们有一个 "good" 哈希函数,我们可以 - 至少在原则上 - 将任意对象存储在键控集合中。

重要注意事项

  1. 数组提供极快的顺序和随机访问(按索引),而插入、删除和增长操作很慢。
  2. Keyed collections 具有您引用的提供极快的插入和删除的优势,但它们本质上是颗粒状的并且会引入复杂性,例如内存碎片(内存管理是一种开销,增加的复杂性意味着增加的成本)。
  3. 当开始发生冲突时,性能会迅速下降。
  4. 天下没有免费的午餐,计算哈希值相对昂贵(与简单地使用索引值或存储的键相比)。
  5. 散列有一个特定的缺点,"natural keys" 和索引没有,那就是它们不提供自然 ordering/sequence。 (根据哈希值顺序处理对象等同于随机处理。)

选择适合其预期用途的数据结构始终很重要(但这就是您引用的 link 的全部内容;-)