Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/148.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么python';s dict实现为哈希表,而std::map是基于树的?_C++_Python_Map_Hashtable - Fatal编程技术网

C++ 为什么python';s dict实现为哈希表,而std::map是基于树的?

C++ 为什么python';s dict实现为哈希表,而std::map是基于树的?,c++,python,map,hashtable,C++,Python,Map,Hashtable,为什么一种语言使用树而另一种语言使用哈希表来表示看似相似的数据结构 c++的映射与python的dict 一个相关的问题是关于哈希表的性能。 请评论我对以下哈希表的理解 树保证有O(logn)。 然而,除非由于可能的冲突,输入之前已知,否则哈希表没有保证。 我倾向于认为,随着问题规模的增大,哈希表的性能将接近O(n)。 因为我还没有听说过一个哈希函数可以随着问题大小的增长动态调整表大小 因此,哈希表只适用于一定范围的问题大小,这就是为什么大多数DB使用树而不是哈希表。 < P>新的C++标准有

为什么一种语言使用树而另一种语言使用哈希表来表示看似相似的数据结构

c++的映射与python的dict

一个相关的问题是关于哈希表的性能。
请评论我对以下哈希表的理解

树保证有O(logn)。
然而,除非由于可能的冲突,输入之前已知,否则哈希表没有保证。
我倾向于认为,随着问题规模的增大,哈希表的性能将接近O(n)。
因为我还没有听说过一个哈希函数可以随着问题大小的增长动态调整表大小


因此,哈希表只适用于一定范围的问题大小,这就是为什么大多数DB使用树而不是哈希表。

< P>新的C++标准有<代码> STD::unOrdEdEdMult类型。IIRC他们希望它也能进入以前的标准,但在讨论过程中没有足够的时间,所以被忽略了。然而,大多数流行的编译器多年来都以这样或那样的方式提供了它

换句话说,不要太担心。为手头的任务使用适当的数据结构


至于你对哈希表的理解,这是不准确的:

我还没有听说过动态调整表的哈希函数 问题规模越大,问题规模越大


所有严肃的哈希表实现都会通过分配一个更大的数组并重新散列所有键来动态调整自己以适应不断增长的输入。虽然这个操作很昂贵,但如果设计得当(很少这样做),性能仍然是按O(1)摊销的。

Python哈希表的填充量永远不会超过2/3。随着尺寸的增长,屏幕会随之调整大小(从8号开始,然后翻两番,直到50000号,然后再翻倍)。这就给了它们分期付款的O(1)插入、删除和查找。过度冲突是可能的,但很少发生。

您对哈希表(以及使用它们的人)的理解是有缺陷的

问题是,哈希表是一个相当模糊的术语。在引擎盖下有许多实现。。。但是首先让我们讨论一下BST(二进制搜索树)的使用


为什么C++使用二叉搜索树?< /p> C++是由Committee设计的,有许多可能的哈希表实现,导致不同的特性,而最流行的BST(红黑树和AVL树)实现具有几乎相同的特性。因此,他们并没有完全拒绝哈希表,他们只是无法确定要选择的特征和向用户公开的细节

见詹姆斯·坎泽的评论,这个提议来得太晚了,詹姆斯问了一个有趣的问题,为什么斯捷潘诺夫没有首先提出。我仍然怀疑选择的数量是罪魁祸首

为什么数据库使用搜索树

首先,让我们确定一个数据库软件。我会选择Oracle,因为它有广泛的文档记录,并且是典型的SQL数据库。Oracle提供两种类型的索引:位图和搜索树

注意:它们不使用二进制搜索树,而是使用B+树,B+树对IO和缓存更加友好

哈希表和搜索树之间有一个根本区别:后者是排序的。许多数据库操作意味着排序:

  • 获取第n个元素
  • 获取前n个元素
  • 获取[a,b]中的元素
在所有这些情况下,哈希表都是无用的

此外,数据库需要处理庞大的数据集(一般来说),这意味着它们需要组织数据以最小化IO(磁盘读/写)。在这里,搜索树的排序性质意味着(在索引中)可能一起访问的元素(因为它们共享很多)也将分组在一起,而不是分散在磁盘的四个角落

最后,Oracle内部可能会在其执行计划中使用哈希表。当执行需要两组行相交的操作时,优化引擎可能会决定将(临时)集存储在哈希表中是最快的方法


现在,关于性能

事实上,搜索树的性能通常是众所周知的,并且易于理解。O(logn)很好且整洁

另一方面,正如我所说,有许多不同的哈希表实现可能,以及处理增长和收缩的策略。。。肯定更复杂

作为结构的一个简单示例,哈希表可以使用:

  • 开放寻址:哈希表是一个元素数组,哈希表示数组中放置元素的插槽,如果插槽已满,则有一种定位另一个插槽的策略。同样的策略也用于搜索
  • bucket:哈希表是指向bucket的指针数组,哈希表示bucket中放置元素的槽。假设桶可以无限增长
这两种策略具有极其不同的特征,后一种特征也取决于bucket实现(简单的实现是使用一个简单的链表)

但是,即使您选择了一个实现,它的性能也是基于散列函数分布的,这取决于输入序列本身



我个人的建议?要在C++中选择<代码> unordeDMAP < /C>和 map ,我只需问自己是否需要排序元素。如果需要对它们进行排序,我将使用
映射
,否则我将使用
无序映射
。大多数情况下,性能都一样好,因此它只是语义

语言设计者或多或少的任意选择。在 C++的例子,我怀疑(但不确定)动机是什么 想要定义复杂度的严格上限:d