unordered_map<类型,布尔值>与设置<TYPE>值
unordered_map<TYPE, bool> vs. set<TYPE>
使用std::unordered_map之类的散列表集合类型与std::set的实际权衡是什么?
对于我正在做的一些偶然的事情(在c++中),我有一个从一对大列表中识别重复项的集合交叉问题。
我的第一个假设是遍历第一个列表并将每个列表插入std::unordered_map<T, bool>
或(std::hash_map)中,其中插入时的值参数始终是true
。然后在hash_map中查找第二个列表中的每个项目。工作假设是每次插入是O(1),每次查找也是O(1)。
然后我开始想也许std::set更合适。一些粗略的在线搜索显示std::set的实现是一个红/黑true,并且插入和/或查找的运行时间可能是O(lgn)而不是O(1)。(对吗?)
我假设两者之间的权衡可能是内存使用和哈希函数的使用(与直接比较相比)。我使用的数据的实际类型只是一个unsigned int。我可以想象,这个问题的动态可能会因为一个更复杂的类型和不同的哈希函数而改变。
假设您有2个列表(例如,L1
和L2
),分别具有N
和M
个元素数量。而且L1
和L2
有独特的元素。(即L#(i) != L#(j)
对应每个i != j
)。
你的第一个算法:
step1:将L1的元素拷贝到unordered_map
U中,时间复杂度:
-
平均情况
O(N)
. -
最坏情况
O(N^2)
.
step2:遍历L2
中的元素,检查每个元素是否存在于U
中。
-
平均情况
O(M) * O(1) = O(M)
. -
最坏情况
O(M) * O(N) = O(M*N)
.
平均情况
O(N) + O(M)
, 线性复杂度。最坏情况
O(N^2) + O(M*N)
, 二次复杂度。
你的第二个算法:
step1:将L1的元素复制到 set
s中,时间复杂度:
平均情况
O(N) * O(log(N))
.最坏情况
O(N) * O(log(N))
.
step2:遍历L2
中的元素,检查每个元素是否存在于S
中。
平均情况
O(M) * O(log(N))
.最坏情况
O(M) * O(log(N))
.
平均情况
O(M) * O(log(N)) + O(N) * O(log(N))
, 线性对数复杂度。最坏情况
O(M) * O(log(N)) + O(N) * O(log(N))
, 线性对数复杂度。
结果:
渐近第一算法在平均情况下获胜。在最坏的情况下,第二种算法会失败。
评论:
- 使用
unordered_set
渐近算法的时间复杂度与第一种算法相同。在实践中更好更快,因为你没有布尔值的冗余。 - 在实践中,由于缓存内存的存在,它的复杂性超过了理论。似乎具有连续内存存储元素的数据结构比具有碎片内存存储元素的数据结构获得更好的性能。Herb Sutter在这个视频讲座中很好地解释了这种效果。
- 所有这些在实践中都是骗局。总是你必须分析你的代码,以确定哪种算法在实践中更快。Eric Brumer在这个视频讲座中很好地解释了这一点。
set<>和map<>通常使用树数据结构实现,因此插入和查找的运行时间为0 (lgn)。
unordered_set<>和unordered_map<>通常使用散列表结构实现,因此插入和查找的性能为0(1)。
有待确定-我不确定为什么set<>和map<>可以作为哈希表和双重链表的组合来实现。其中哈希表中的每个元素都封装了值和指向插入的前一个/下一个节点的指针。这是以后的问题了
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 呼叫运营商<<临时
- 如何防止clang格式在流运算符调用之间添加换行符<<
- <<操作员在下面的行中工作
- EASTL矢量<向量<int>>连续的
- C - 创建矢量&lt; vector&lt; double&gt;&gt;矩阵具有分配而不是inizializ
- 为什么将此对向量&lt; map&lt; int,int&gt;&gt;中的地图进行更新.失败
- C :对矢量进行排序&lt; struct&gt;(结构有2个整数)基于结构的整数之一
- 明确的专业化“ CheckIntmap&lt;&gt;”实例化
- 什么是模板&lt;&gt;inline bla bla
- 编辑C Qlist&lt; object*&gt; gt;QML代码和一些QML警告中的模型
- eigen :: llt&lt;eigen :: matrixxd&gt;具有不完整的类型
- 错误,包括&lt; ctype&gt;在原子上使用C 11
- std::vector<;uint8_t>;当C++11/14启用时,手动复制而不是调用memcpy
- 如何加入向量&lt; int&gt;到C 中的单个INT
- 是std :: set&lt; std :: future&gt;不可能存在
- 是numeric_limits&lt; int&gt; :: is_modulo从逻辑上矛盾
- opencv 2.4.7在iOS错误背景_segm.hpp #include&lt; list&gt;未找到
- 在修改列表后,std :: list&lt; t&gt; :: end()的值是否会更改
- ///<评论></评论>在Visual Studio中