当实现字典时(“我想通过他们的客户ID查找客户数据”),使用的典型数据结构是哈希表和二进制搜索树。例如,我知道C ++ STL库使用(平衡的)二进制搜索树实现字典(它们称为地图),而.NET框架在后台使用哈希表。
这些数据结构的优缺点是什么?在某些情况下还有其他合理的选择吗?
请注意,对于键具有强大的基础结构的情况,例如,它们都是1到n之间的整数或类似的东西,我并不特别感兴趣。
当实现字典时(“我想通过他们的客户ID查找客户数据”),使用的典型数据结构是哈希表和二进制搜索树。例如,我知道C ++ STL库使用(平衡的)二进制搜索树实现字典(它们称为地图),而.NET框架在后台使用哈希表。
这些数据结构的优缺点是什么?在某些情况下还有其他合理的选择吗?
请注意,对于键具有强大的基础结构的情况,例如,它们都是1到n之间的整数或类似的东西,我并不特别感兴趣。
Answers:
简短的答案是,在大多数情况下,哈希表会更快,但在最坏的情况下可能会非常糟糕。搜索树具有许多优点,包括驯服的最坏情况下的行为,但在典型情况下则较慢。
当您将数据局部性添加到混合中时,哈希表的效果很差。它们之所以起作用是因为它们将相关元素存储得相距很远,这意味着如果应用程序按顺序查找共享前缀的元素,它将不会从缓存效果中受益。如果应用程序实质上进行随机查找,则这无关紧要。
支持搜索树的另一个因素是它们是不可变的数据结构:如果您需要复制一棵树并更改其中的一些元素,则可以共享大多数数据结构。如果要获取哈希表的副本,则需要复制整个指针数组。另外,如果您使用的是纯粹的功能语言,则通常不能选择哈希表。
特别是,如果您需要键的顺序,例如,如果您希望能够按字母顺序列出键,则哈希表无济于事(您需要对其进行排序),而可以直接按顺序遍历搜索树。
您可以以哈希树的形式组合二进制搜索树和哈希表。哈希树根据其哈希将关键字存储在搜索树中。例如,这在纯函数式编程语言中很有用,在这种语言中,您要处理不具有易于计算的顺序关系的数据。
当键是字符串(或整数)时,特里可以是另一个选择。特里树是一棵树,但其索引与搜索树的索引不同:您以二进制形式编写密钥,然后左移为0,右移为1。因此,访问成本与密钥的长度成正比。可以压缩尝试以删除中间节点;这被称为patricia trie或基数树。基数树可以胜过平衡树,特别是当许多键共享一个公共前缀时。