哈希表与二叉树


30

当实现字典时(“我想通过他们的客户ID查找客户数据”),使用的典型数据结构是哈希表和二进制搜索树。例如,我知道C ++ STL库使用(平衡的)二进制搜索树实现字典(它们称为地图),而.NET框架在后台使用哈希表。

这些数据结构的优缺点是什么?在某些情况下还有其他合理的选择吗?

请注意,对于键具有强大的基础结构的情况,例如,它们都是1到n之间的整数或类似的东西,我并不特别感兴趣。


1
我会激怒您,但您不能只说“ 1到n之间的整数”,因为在这种情况下,数组将超出所有其他数据结构:-)。“字符串”似乎很公平,并且涵盖了大多数情况。
jmad 2012年

@jmad他说他对该案感兴趣。
2012年

@Joe我以为很明显我考虑了这一点。无论如何,这并不是给出最糟糕的密钥示例的理由。
jmad 2012年

1
实际上,.NET既有使用树实现的字典,又有使用哈希表实现的字典(自2011年标准以来,C ++也是如此)。
sepp2k 2012年

Answers:


26

ñ

简短的答案是,在大多数情况下哈希表会更快,但在最坏的情况下可能会非常糟糕。搜索树具有许多优点,包括驯服的最坏情况下的行为,但在典型情况下则较慢。

ØGñØG2ñ

2ñØ1个

Ø1个

  • Øñ
  • Ø1个

当您将数据局部性添加到混合中时,哈希表的效果很差。它们之所以起作用是因为它们将相关元素存储得相距很远,这意味着如果应用程序按顺序查找共享前缀的元素,它将不会从缓存效果中受益。如果应用程序实质上进行随机查找,则这无关紧要。

支持搜索树的另一个因素是它们是不可变的数据结构:如果您需要复制一棵树并更改其中的一些元素,则可以共享大多数数据结构。如果要获取哈希表的副本,则需要复制整个指针数组。另外,如果您使用的是纯粹的功能语言,则通常不能选择哈希表。

ķ1个ķ2Hķ1个=Hķ2

特别是,如果您需要键的顺序,例如,如果您希望能够按字母顺序列出键,则哈希表无济于事(您需要对其进行排序),而可以直接按顺序遍历搜索树。

您可以以哈希树的形式组合二进制搜索树和哈希表。哈希树根据其哈希将关键字存储在搜索树中。例如,这在纯函数式编程语言中很有用,在这种语言中,您要处理不具有易于计算的顺序关系的数据。

当键是字符串(或整数)时,特里可以是另一个选择。特里树是一棵树,但其索引与搜索树的索引不同:您以二进制形式编写密钥,然后左移为0,右移为1。因此,访问成本与密钥的长度成正比。可以压缩尝试以删除中间节点;这被称为patricia trie或基数树。基数树可以胜过平衡树,特别是当许多键共享一个公共前缀时。


2
BST是否也具有不良的数据局部性?
svick 2012年

@svick它们可能会或可能不会,取决于节点的分配方式。增加树的精巧度可以在不影响运行时间的情况下提供帮助(代价是更大,更复杂的代码)。
吉勒斯(Gillles)“所以-别再邪恶了”

2
在BST上,很容易“按顺序”获取元素,对于哈希表而言,这是不可能的。
vonbrand 2013年

除了出于安全原因,如果哈希表的平均情况比二叉树的情况好,那么为什么哈希表的最坏情况时间不重要呢?我认为实用程序/用户便利性与树完成所需的时间大致呈线性关系,因此,预期(平均)值应该很重要。
Kelmikra

@ Kyth'Py1k“要完成的树”是什么意思?哈希表的目的是一次访问一个值,而不是整个树,否则列表或数组会更好。即使在平均值很重要的情况下(并非总是如此,例如,当您有实时约束时),它还是在给定情况下发出的请求中的平均值,通常在表上根本不一致—例如,偏向某个前缀。
吉尔(Gilles)'所以
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.