Data structures 用二叉搜索树实现哈希表

Data structures 用二叉搜索树实现哈希表,data-structures,hashtable,binary-search-tree,Data Structures,Hashtable,Binary Search Tree,摘自编码访谈,第71页: 或者,我们可以用BST实现哈希表 保证O(logn)查找时间,因为我们可以保留树 平衡的此外,我们可能会使用更少的空间,因为大型阵列没有 一开始就需要分配更长的时间 我知道链表、哈希表和BST的基本知识,但我无法理解这些行。这到底是什么意思?最终的数据结构会是Trie吗 该部分的全文说明,最后一段是您询问的内容: 哈希表是一种将键映射到值的数据结构,用于高效查找。在一个 非常简单的哈希表实现,哈希表有一个底层数组和 散列函数。要插入对象及其键时,哈希函数将映射 整数的键

摘自编码访谈,第71页:

或者,我们可以用BST实现哈希表 保证O(logn)查找时间,因为我们可以保留树 平衡的此外,我们可能会使用更少的空间,因为大型阵列没有 一开始就需要分配更长的时间

我知道链表、哈希表和BST的基本知识,但我无法理解这些行。这到底是什么意思?最终的数据结构会是Trie吗

该部分的全文说明,最后一段是您询问的内容:

哈希表是一种将键映射到值的数据结构,用于高效查找。在一个 非常简单的哈希表实现,哈希表有一个底层数组和 散列函数。要插入对象及其键时,哈希函数将映射 整数的键,表示数组中的索引。然后将对象存储在 这个指数

然而,通常情况下,这并不完全正确。在上述实现中,哈希 所有可能键的值都必须是唯一的,否则可能会意外覆盖数据。这个 数组必须非常大,所有可能的键的大小都必须非常大,才能防止出现这种情况 “碰撞。”

我们没有创建一个非常大的数组并将对象存储在索引散列(key)中,而是 可以使数组更小,并将对象存储在索引哈希(键)处的链表中% array_length.要获取具有特定键的对象,必须在链表中搜索 这把钥匙

或者,我们可以用二叉搜索树实现哈希表。那么我们可以 保证0(logn)的查找时间,因为我们可以保持树的平衡。另外,, 我们可能会使用更少的空间,因为不再需要在最短的时间内分配大型阵列 开始

所以他们正在讨论使用BST(二进制搜索树)来处理冲突。实际上,使用BST作为唯一的数据结构是没有意义的,因为经过适当调整的哈希表的全部要点是,查找的顺序是
O(1)
,远远好于BST的
O(logn)
。此外,使用BST完全实现哈希表意味着它实际上不是哈希表:-)

但是,考虑一下,当哈希表中有冲突时,处理它们的一种常见方法是让每个桶包含其项的链表。在退化的情况下(所有项散列到同一个bucket),最终只得到一个链表,

O(1)
变成
O(n)

因此,每个bucket都有一个BST,而不是一个链表。在单个bucket有许多项的情况下(前面提到的冲突),就不再有
O(n)
搜索复杂性

使用哈希函数在
O(1)
中查找bucket,然后在
O(log n)
中搜索BST(如果存在冲突)。在最好的情况下(每桶一件),它仍然是
O(1)
。最坏的情况是
O(logn)
而不是
O(n)

最初让我担心的唯一一件事是,他们还讨论了一个事实,即不再需要大量拨款。如果它是一个共享hash/BST组合,您仍然需要分配整个hash表,这样看起来就不协调了


但是,从上下文来看(“…因为不再需要分配大型数组…”),它们似乎意味着它们可以使双数据结构的哈希表部分更小,因为冲突的处理效率更高。换句话说,与带有冲突链表的1000个元素的哈希表不同,您可以使用100个元素的哈希表,因为如果使用BST,冲突不会对搜索时间造成太大损害。

您在这里合并了一些术语

  • 其想法是以两层方式使用数组和BST实现哈希表。如果没有冲突,仍然可以向哈希中添加值,但如果有冲突,则可以解决使用BST检索冲突元素的性能问题

  • A是完全不同的东西;根据您试图存储的内容,您可能无法将其应用于哈希函数

对于树,O(logN)绑定是最坏的情况。让我们这样看。 我们插入45,33,55,66,22,然后将45作为根节点,33和55在级别1,22中,66在级别2中

因此,如果要对值45进行散列,它仍然是一个O(1)操作…只有在级别2中查找节点时,它的数量才会接近O(logN)…树可以是RB树/AVL树,这样它就不会退化为链表…您会损失一些tiem效率,但会在空间效率方面进行弥补

另一个优点是,您不需要担心哈希表中的冲突。


基本上,您可以动态分配节点,并且不会在哈希表中未使用的存储桶上浪费任何空间……例如,如果您使用具有预定义大小的静态哈希表(buschkets),那么,这将导致空间效率低下的实现。

我想BST只用于冲突;它得到了一个类似于链式散列方法的类比,该方法需要花费O(N)来检索;在这种情况下,BST是最好的。实际上,C++ STD::MAP是用BST作为整体来实现的。优点是:1。不再需要担心碰撞2。键是有序的,这样您就可以按顺序遍历。我认为作者的意思是这样的,而不是只使用BST来处理冲突。我的想法也是,我只是有点担心他们的评论“另外,我们可能会使用更少的空间,因为一开始就不再需要分配大数组”。是的。我不会否认导致这一部分的背景