插入、删除、查找中哪一个执行得更快?哪一个需要更少的内存和更少的时间来从内存中清除它。任何解释都受到热烈欢迎!!!
对于特定用途,您应该尝试使用您的实际数据和使用模式,看看哪个实际上更快......有足够的因素假设其中任何一个总是“获胜”是很危险的。
无序映射/哈希表的实现和特点
在学术上 - 随着元素数量向无穷大增加,std::unordered_map(这是 C++ 库提供的计算科学术语“哈希图”或“哈希表”)上的操作将倾向于继续占用相同的时间量 O(1)(忽略内存限制/缓存等),而对于 std::map(平衡二叉树),每次元素数量翻倍时,它通常需要进行额外的比较操作,所以它逐渐变慢 O(log2n)。
std::unordered_map implementations necessarily use open hashing:基本的期望是会有一个连续的“桶”数组,每个在逻辑上都是一个包含任何散列到其中的值的容器。
它通常用于将哈希表描绘为vector<list<pair<key,value>>>,其中从向量元素获取值涉及至少一个指针解引用,因为您遵循存储在存储到初始列表节点;插入/查找/删除操作的性能取决于列表的大小,平均等于unordered_map 的load_factor。
如果max_load_factor 降低(默认值为 1.0),那么在插入过程中会发生更少的冲突,但会发生更多的重新分配/重新散列和更多的内存浪费(这会通过增加缓存未命中来影响性能)。
这个最明显的unordered_map 实现的内存使用涉及bucket_count() list-head-iterator/pointer-sized 桶的连续数组和每个键/值对的一个双向链表节点。通常,bucket_count() + 2 * size() 额外的开销指针,针对实现可能执行的动态内存分配请求大小的任何四舍五入进行了调整。例如,如果您要求 100 个字节,您可能会得到 128、256 或 512。实现的动态内存例程也可能使用一些内存来跟踪已分配/可用区域。
不过,C++ 标准为实际实现留出了空间,让他们自己做出一些性能/内存使用决策。例如,他们可以在分配一个新的更大的数组后将旧的连续存储桶数组保留一段时间,因此可以逐渐将值重新散列到后者中,以降低最坏情况下的性能,但会以平均情况性能为代价在操作过程中会查询这两个数组。
maps/平衡二叉树的实现及特点
map 是二叉树,可以预期使用指针链接不同的堆内存区域,这些区域由对new 的不同调用返回。除了键/值数据外,树中的每个节点都需要父、左和右指针(如果丢失,请参阅wikipedia's binary tree article)。
比较
因此,unordered_map 和 map 都需要为键/值对分配节点,前者通常具有两个指针/迭代器开销用于上一个/下一个节点链接,而后者具有三个用于父/左/正确的。但是,unordered_map 还具有用于 bucket_count() 存储桶的单个连续分配 (== size() / load_factor())。
对于大多数用途而言,内存使用量的差异并不大,而且一个额外区域的释放时间差异不太可能引起注意。
另一种选择
对于那些预先填充容器然后重复搜索而无需进一步插入/擦除的情况,有时使用排序向量可能是最快的,使用标准算法搜索binary_search、equal_range、lower_bound、@987654329 @。这具有单个连续内存分配的优点,这对缓存更加友好。它总是优于 map,但 unordered_map 可能仍然更快 - 如果你在乎,请测量。