比较两个(非STL)贴图是否相等
Compare two (non-STL) maps for equality
我们使用的第三方库本质上是一个地图/字典。它没有提供任何平等测试两个对象的方法,我们需要这样做。
更具体地,两个映射S1&S2被认为是相等的,如果:
- S1中的每一个键都是S2中的一个键
- S2中的每一个键都是S1中的一个键
- 对于S1中的每个键K,S1[K]==S2[K]
请注意,每个映射中的内部排序是不相关的,可能不可靠,因此不可能直接比较内部结构/成员。我们确实有办法比较键和值以实现相等。
做这件事最简洁的算法是什么?伪C++很好,因为set类上的API与我可以翻译的std::map足够接近。
比较的大小
-
如果大小相等
-
迭代第一组中的密钥,对于每个密钥:
-
检查第二组中是否存在密钥
-
检查密钥的元素是否等于
-
-
-
若至少有一个元素不相等,第一个集合中的一个键在第二个集合中不存在,或者大小不相等,则集合不相等。
只要正确地知道存储在集合中的最大值,这个方法就有效。取一个大小为maximum value+1
的数组,并将其初始化为0
。然后在第一个集合和increment
中,通过其对应的value
迭代"key"位置的数组值。
现在,在第二个集合和decrement
中,用其value
迭代索引key
处的数组中的值。
最后检查所有数组值是否为zero
。如果不是,则它们是unequal
,否则它们是equal
。
时间复杂度:O(N)
内存:O(max_value)
假设您的映射API具有迭代器(或索引),有序,不包含重复,并且还将其键和映射类型存储为嵌套的typedef,则您可以在O(N)
时间中实现std::map::operator==
的相同语义:
#include <functional> // less
#include <algorithm> // includes
// O(N) complexity
template<class MyMap, class KeyCmp = std::less<typename MyMap::key_type, class TCmp = std::equal<typename MyMap::mapped_type> >
bool set_equality(MyMap const& lhs, MyMap const& rhs, KeyCmp keycmp, TCmp tcmp)
{
typedef typename MyMap::value_type Pair;
return
lhs.size() == rhs.size() &&
std::includes(
lhs.begin(), lhs.end(),
rhs.begin(), rhs.end(),
[](Pair const& p1, Pair const& p2){
return keycmp(p1.first, p2.first) && tcmp(p1.second, p2.second);
})
;
}
我认为要回答的一个主要问题是在字典结构中进行一次查找的成本有多高。如果你有一个hashmap的O(1),那么像utnapistim所建议的比较循环的复杂性将是O(n)*O(1。如果底层字典是std::map,那么将有O(logn)查找,使其总体为O(n*logn)。如果您的dict是在未排序的数组或列表之上实现的,那么您将有O(n)个查找,使其总体为O(n^2)。
我之所以提到这些,是因为你还可以对这两本词典进行排序并比较结果。对它们进行排序是O(n*logn),就像std::map一样,所以在不知道查找复杂性的情况下,您无法决定对序列进行排序的成本是高还是低。
还有一个方面我想提一下,那就是词典的排序。你说你不能假设任何东西,但据我所知,只有一种常见的结构不能保证内容相等意味着顺序相等,即未排序的数组或链表。然而,由于查找是O(n),所以它作为字典的性能很差,所以不太可能有人选择它作为底层容器。写这篇文章时,我想知道如果哈希图有不同的桶大小,也许还有历史记录,它们是否能保证,我真的不确定。不过,我确信最好的算法取决于字典的查找复杂性,所以我会尝试了解更多关于这方面的信息。即使是测量也比什么都不知道要好。IMHO可以接受一个有充分记录的、依赖于特定行为的黑客攻击。
- 如何检查两个 std::向量在小于 O(n) 的时间复杂度内是否相等
- 是否可以在 OpenGL 中的同一调用中呈现两个具有不同索引起点的不同缓冲区?
- 检查两个节点在子节点上是否具有相同状态的更优雅的方法
- 如何巧妙地编写两个函数——一个用于检查是否存在解决方案,另一个用于获取所有解决方案
- 使用XOR查找O(n)-解决方案中的两个字符串是否为变位符
- 给定一个大小为 N 的数组 S,检查是否可以将序列拆分为两个序列
- 具有相同特征的两个对象是否只在内存中存储一次?无论定义它们的函数是什么,都是不同的
- 如何更好地检查两个 char 变量是否在一组值中?
- 是否有一种标准方法来计算两个 asctime() 值之间的天数
- 是否可以使用非常量指针调用非常量函数,以及当两个unique_ptrs指向同一个对象时程序的行为方式?
- 检查两个模板参数是否相同
- 是否可以在 for 循环中添加两个浮点数?
- 是否允许三元运算符在C++中计算两个操作数?
- 使用 SET(C++) 检查两个给定字符串是否是字谜时出现运行时错误
- 使用 std::vector::swap 方法在C++中交换两个不同的向量是否安全?
- 检查两个向量是否并行的最有效方法
- 检查两个图是否为补码的功能
- gtest:检查字符串是否等于两个字符串之一
- 如何在c/c++中检查两个任意内存范围是否重叠
- 图问题:找出两个节点是否在每个节点的O(1)时间和O(2)存储中共享同一分支