查找 3 个 C++ 中的 1 个集合唯一的单词
Posted
技术标签:
【中文标题】查找 3 个 C++ 中的 1 个集合唯一的单词【英文标题】:Find words that are unique for 1 set out of 3 C++ 【发布时间】:2020-03-13 13:23:46 【问题描述】:我有 3 个包含单词的集合。
a: car, boat, table, ball
b: car, goat, helicopter
c: square, car, goat, boat
我需要创建一个向量或集合,其中包含仅包含在集合 a 中的单词。
所以答案是:
result: table, ball
我尝试使用 set_difference 和 set_intersection 来实现它,但到目前为止没有运气。你能给我一些建议吗?
我试过了
set_difference(a.begin(), a.end(), b.begin(), b.end(), res.begin());
set_difference(res.begin(), res.end(), c.begin(), c.end(), res.begin());
但是结果是空的
【问题讨论】:
std::set_difference
是此作业的标准工具。您可以使用它显示您的代码,我们可以帮助您修复它吗?
您在使用std::set_difference
之前是否对数组进行了排序?
实际上我无法理解如何将 3 套而不是 2 套放入std::set_difference
你没有。您对a
和b
运行差异创建输出d
。然后你对 d
和 c
运行差异创建你的结果集。
第二行写错了。您在迭代 res
时正在修改它。您应该使用final_res
变量来存储第二个结果。
【参考方案1】:
你的错误在这里:
set_difference(res.begin(), res.end(), c.begin(), c.end(), res.begin()); // ^ ^ ^
您遍历res
并将结果写入同一个集合中。您需要另一组来存储结果。
解决方案是:
std::set<std::string> a "car", "boat", "table", "ball";
std::set<std::string> b "car", "goat", "helicopter";
std::set<std::string> c "square", "car", "goat", "boat";
std::set<std::string> tmp;
std::set<std::string> res;
// Difference between a and b --> stored in tmp
std::set_difference(a.begin(), a.end(), b.begin(), b.end(), std::inserter(tmp, tmp.begin()));
// Difference between tmp and c --> stored in res
std::set_difference(tmp.begin(), tmp.end(), c.begin(), c.end(), std::inserter(res, res.begin()));
for(const std::string & s : res)
std::cout << s << '\n';
输出:
球 表
Live example
注意:如果我们查看std::set_difference
的文档,我们可以看到:
将排序范围 [first1, last1) 中未在排序范围 [first2, last2) 中找到的元素复制到从 d_first 开始的范围内。
结果范围也被排序。 等价元素被单独处理,即如果某个元素在[first1,last1)中找到m次,在[first2,last2)中找到n次,则将其准确复制到d_first std::max(m-n, 0 ) 次。结果范围不能与任何一个输入范围重叠。
强调我的
所以如果你想使用另一个不保证其元素唯一性的容器(例如std::vector
),你需要自己确保每个元素不会在你的容器中出现多次。
注意2:如果你不想打扰tmp
set(拿到res
set后就没用了),你可以把它放在一个bloc中,这样它之后会被销毁:
std::set<std::string> res;
std::set<std::string> tmp;
std::set_difference(a.begin(), a.end(), b.begin(), b.end(), std::inserter(tmp, tmp.begin()));
std::set_difference(tmp.begin(), tmp.end(), c.begin(), c.end(), std::inserter(res, res.begin()));
// tmp destroyed here
Live example
【讨论】:
【参考方案2】:如果不共享您的代码,我们只能猜测您的代码做错了什么。
这就是我所做的。我将差异逻辑包装在一个助手 operator-
中。我故意使用std::unordered_set
,因为它们不能直接在std::set_difference
中使用。
#include <algorithm>
#include <iostream>
#include <iterator>
#include <string>
#include <unordered_set>
#include <vector>
using std::cout;
using std::inserter;
using std::ostream;
using std::set_difference;
using std::sort;
using std::string;
using std::unordered_set;
using std::vector;
namespace
unordered_set<string> operator-(unordered_set<string> const& minuend, unordered_set<string> const& subtrahend)
vector<string> m(minuend.begin(), minuend.end());
vector<string> s(subtrahend.begin(), subtrahend.end());
sort(m.begin(), m.end());
sort(s.begin(), s.end());
unordered_set<string> diff;
set_difference(m.begin(), m.end(), s.begin(), s.end(), inserter(diff, diff.begin()));
return diff;
ostream& operator<<(ostream& out, unordered_set<string> const& container)
char const* sep = " ";
out << "";
for (auto const& s : container)
out << sep << "\"" << s << "\"";
sep = ", ";
out << " ";
return out;
int main()
auto a = unordered_set<string> "car", "boat", "table", "ball" ;
auto b = unordered_set<string> "car", "goat", "helicopter" ;
auto c = unordered_set<string> "square", "car", "goat", "boat" ;
auto d = a - b - c;
cout << d << "\n";
更新回答 Fareanor 的问题
你为什么使用 std::unordered_set(而不是 std::set)?
我选择了 unordered_set 来证明 set_difference 需要一个有序的容器。 unordered_set 缺少该功能。
原始海报,在原始未经编辑的问题中,没有提供使用哪种容器的详细信息。
为什么要将它转换成需要排序的 std::vector(而不是转换成 std::set)?
向量是一个非常有效的容器,因为其中的元素具有局部性,因此具有良好的缓存。这是我的首选容器。
一个集合有更多的内存分配,因为它是一个节点网格,并且缺乏局部性。
无论如何,包含的字符串对象可能缺少局部性,因为它基本上是一个指向字符数组的智能指针。但由于小字符串优化 (SSO) 和这些都是小字符串,它也不会在堆外分配。
在原发帖人的场景中,每个容器中只有几件物品,因此效率问题可以忽略不计。但值得考虑的是,如果问题域扩大了。
我认为你应该使用 std::set (至少没有来自 OP 的任何澄清),如果用户得到一个 std::unordered_set ,则由他将其转换为适当的 std ::set 然后打电话给你的operator-()
。
这是一个可行的选择。由于当时缺乏上下文,我认为这是“更糟糕的情况”,因为 unordered_set 容器不满足 set_difference 算法的要求。
【讨论】:
我喜欢你的想法,它非常优雅。但是有几件事我不明白:你为什么使用std::unordered_set
(而不是std::set
)?为什么将其转换为需要排序的std::vector
(而不是转换为std::set
)?我认为您应该使用std::set
(至少没有任何来自OP的澄清),如果用户得到std::unordered_set
,则由他将其转换为正确的std::set
,然后致电您的@987654333 @.以上是关于查找 3 个 C++ 中的 1 个集合唯一的单词的主要内容,如果未能解决你的问题,请参考以下文章
将浮点数组写入和附加到 C++ 中 hdf5 文件中的唯一数据集