在我的代码中,我必须比较以随机顺序作为列表返回的结构的键,我需要检查两个结构是否具有相同的键元素,忽略顺序,只比较唯一的元素。
目前,我使用的代码类似于下一个示例中显示的代码:
#include <list>
#include <set>
#include <string>
template<typename T>
auto areListsAsSetsEqual(const std::list<T> &a, const std::list<T> &b) -> bool {
auto aSet = std::set<T>{a.begin(), a.end()};
auto bSet = std::set<T>{b.begin(), b.end()};
return aSet == bSet;
}
auto main() -> int {
auto x = std::list<std::string>{"red", "blue", "yellow", "green", "green"};
auto y = std::list<std::string>{"blue", "green", "yellow", "red", "red"};
auto z = std::list<std::string>{"green", "red", "yellow"};
auto xyEqual = areListsAsSetsEqual(x, y);
assert(xyEqual == true);
auto xzEqual = areListsAsSetsEqual(x, z);
assert(xzEqual == false);
return 0;
}
它工作正常,代码简短可靠,但是对于每次比较,都必须创建两个新的集合,并且必须复制这两个列表中的所有元素。
是否有更高效、更优雅的方法来比较两个列表中相同的唯一元素,同时使用更少的CPU和/或内存?
3条答案
按热度按时间bvjveswy1#
这里有一个不同的镜头,它只需要一个新的容器,并且只复制一个列表。
第一个列表被复制到
std::unordered_map
中,每个键被设置为true
。第二个列表被迭代并搜索Map(O(1))。如果没有找到,我们可以立即返回。如果找到,键被设置为false
。然后我们必须搜索unordered_map
,看看是否有任何元素处于true
状态。我还没有运行任何基准测试,所以需要测试来看看这个解决方案是否更有效。理论上,两者都是O(3N),但是平均运行时间需要测试。
但是,尽管运行时效率的提高是模糊的,但这种方法确实提供了明显的空间效率优势。您当前的算法目前需要约2N个空间,而我的算法更接近N。
vjrehmav2#
为完整起见:你也可以尝试使用std算法。假设你不想修改你的输入,你需要拷贝。(对于只有一个拷贝的解决方案,见@sweenish answer。)
这种解决方案在“大O”方面不会更快。但它使用顺序容器作为中间存储,这在现代硬件上可能更高效。与当今的优化一样,您必须使用代表性数据进行测量。
5f0d552i3#
为了完整回答这个问题,最快的算法大致基于sweenish的答案,但不需要原始数据的副本。因此,在以下两个条件下,以下算法上级:
std::string
或一般的字符串。我使用了大量的测试数据,这些数据使用了大小为4到128个字符的
std::string
密钥和0到32个元素的密钥集,对带有小突变的密钥集进行了200'000次比较,得到了以下结果:| 执行情况|每次呼叫的平均时间|平均时间(如果相等)|速度增益|
| - ------|- ------|- ------|- ------|
| 原始的|0.005232毫秒|0.005444毫秒|1×|
| 卡巴|0.004337毫秒|0.004275毫秒|1.21倍|
| 瑞典的|0.002796毫秒|0.003919毫秒|1.87倍|
| 该解决方案|0.000566毫秒|0.001305毫秒|9.24倍|
该算法还具有最低的内存使用率。