持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天,点击查看活动详情
(欢迎大家关注我的微信公众号——控制工程研习,上面会分享很多我学习过程中总结的笔记。)
unordered_map的底层结构是什么?(来自理想汽车面试题)
答案:
实现都采用的是哈希表存储结构。更准确地说,是用“链地址法”(又称“开链法”)解决数据存储位置发生冲突的哈希表。
分析:
undered_map介绍:
无序映射(unordered_map)是关联容器,用于存储由键值和映射值组合而成的元素,并允许基于键快速检索各个元素。
在unordered_map中,键值通常用于唯一标识元素,而映射值是与该键关联的内容的对象。键和映射值的类型可能不同。
在内部,unordered_map中的元素没有按照它们的键值或映射值的任何顺序排序,而是根据它们的散列值组织成桶以允许通过它们的键值直接快速访问单个元素(具有常数平均时间复杂度)
unordered_map容器比映射容器更快地通过它们的键来访问各个元素,尽管它们通过其元素的子集进行范围迭代通常效率较低。
无序映射实现直接访问操作符(operator []),该操作符允许使用其键值作为参数直接访问映射值。
容器中的迭代器至少是前向迭代器。
unordered_map底层实现:
unordered_map底层是用开链法来解决哈希冲突的,用哈希桶实现的。
如图:
template<typename K, typename V> //每个节点的结构
struct HashNode{
pair<K, V> _kv;
HashNode<K,V>* _next;
HashNode(pair<K,V> p) :_next(NULL) , _kv(p) {}
};
template<typename K, typename V, class HashFunc = _HashFunc<K>> //哈希表的结构,第三个参数是仿函数,为了实现可以存储string
class HashTable{
protected:
vector<Node*> _table;
size_t _size;
};
(1)用一个vector来作为一个指针数组来存储节点的指针,_size来保存当前哈希表中的有效元素个数。
(2)由于是K/V结构,所以选择一个pair的结构来存储K/V。
(3)vector中的每一个元素都指向一个链表,所有节点中需要一个next域的指针来指向下一个节点(采用单链表表结构)。所以unordered_map的扩容机制与vector类似。
(4)采用模板来实现哈希表可以存储任意数据类型的目的。
(5)使用了仿函数技术(为了实现可以存储string)。
unordered_map与map的区别:
优点 | 缺点 | 适用场合 | |
---|---|---|---|
map | map内部实现是红黑树,有序性是map结构最大的优点,其元素的有序性在很多应用中都会简化很多的操作,其复杂度为logN。 | 空间占用率高,因为每一个节点都需要额外保存父节点,孩子节点以及红/黑性质,使得每一个节点都占用大量的空间。 | 对于那些有顺序要求的问题,用map会更高效一些。 |
unordered_map | 内部实现是哈希表,因此其查找速度非常的快,复杂度为O(1)。 | 更改哈希表的大小,重构哈希表比较耗费时间。 | 对于查找问题,unordered_map会更加高效一些。 |