【问题标题】:Algorithm for finding most present value in containers在容器中寻找最大现值的算法
【发布时间】:2016-08-26 15:49:02
【问题描述】:

我有以下问题我有一个std::set 的向量现在我想计算元素,它位于大多数集合中。 例如: 如果集合是 {1,2,3,4}、{2,4,5} 和 {2,7,8},我希望算法输出 2,因为 2 在 3 个集合中,而其他所有元素都不是。 我目前解决这个问题的尝试使用了一个映射,它在集合中映射一个计数器值,然后遍历所有集合。 我确定我需要遍历所有集合,但是我可以使用 <algorithm> 标头中的一些算法来解决这个问题吗?

【问题讨论】:

  • 如果您包含“手动”地图解决方案以供参考,那就太好了。
  • @hyde 为什么?很容易猜到它的作用。
  • @Ven 一方面,当存在具有正确变量等的现有模板时,编写答案代码要容易得多。二,具有相关代码的问题更容易获得支持(这有助于获得好的答案),因为代码。第三,这有助于证明 OP 在询问之前确实了解他们所询问的内容并且“已经完成了他们的作业”。

标签: c++ algorithm c++11 containers


【解决方案1】:

使用for_each的解决方案:

std::set<std::set<std::string>> sets {s1,s2,s3,s4}; // incurs a copy on each set
std::unordered_map<std::string, int> all;
std::for_each(sets.begin(), sets.end(), [&all](const std::set<std::string> &s) { // outer loop: each set in sets
    std::for_each(s.cbegin(), s.cend(), [&all](const std::string &string) { // nested loop
         all[string]++;
    });
});
for (const auto &p : all)
    std::cout << p.first << " = " << p.second << "\n";

See it live on Coliru!

使用单个向量并累积的另一种解决方案:

std::set<std::string> s1 {"a", "b", "c"};
std::set<std::string> s2 {"a", "x", "d"};
std::set<std::string> s3 {"a", "y", "d"};
std::set<std::string> s4 {"a", "z", "c"};
std::vector<std::string> vec;
// flatten sets into the vector.
vec.insert(vec.begin(), s1.begin(), s1.end());
vec.insert(vec.begin(), s2.begin(), s2.end());
vec.insert(vec.begin(), s3.begin(), s3.end());
vec.insert(vec.begin(), s4.begin(), s4.end());
for (const auto &p : std::accumulate(vec.begin(), vec.end(), std::unordered_map<std::string, int>{}, [](auto& c, std::string s) { c[s]++; return c; })) // accumulate the vector into a map
    std::cout << p.first << " = " << p.second << "\n";

See it live on Coliru!

如果复制成本负担过大,您可以改为在每个std::sets 上使用部分应用函数:

std::set<std::string> s1 {"a", "b", "c"};
std::set<std::string> s2 {"a", "x", "d"};
std::set<std::string> s3 {"a", "y", "d"};
std::set<std::string> s4 {"a", "z", "c"};
std::unordered_map<std::string, int> all;
auto count = [&all](const auto& set) { std::for_each(set.begin(), set.end(), [&all](std::string s) { all[s]++; }); };
count(s1); // apply a for_each on each set manually.
count(s2);
count(s3);
count(s4);
for (const auto &p : all)
    std::cout << p.first << " = " << p.second << "\n";

See it live on Coliru!

【讨论】:

    【解决方案2】:

    并计算交叉点:

    #include <iostream>
    #include <algorithm>
    #include <set>
    #include <iterator>
    
    int main()
    {
        std::set<int> s1{ 1, 2, 3, 4 };
        std::set<int> s2{ 2, 4, 5 };
        std::set<int> s3{ 2, 7, 8 };
    
        std::multiset<int> s4;
    
        std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(),
            std::insert_iterator<std::multiset<int>>(s4, s4.begin()));
    
        std::set_intersection(s4.begin(), s4.end(), s3.begin(), s3.end(),
            std::insert_iterator<std::multiset<int>>(s4, s4.begin()));
    
        auto max = std::max_element(s4.begin(), s4.end(),
            [&s4](int a, int b) { return s4.count(a) < s4.count(b); });
    
        std::cout << "most present == " << *max << '\n';
    }
    

    【讨论】:

    • 对于大型问题实例,似乎建议始终与最低基数的两个集合相交 - 在第一步之后意味着当前与尚未处理的最小集合相交
    【解决方案3】:

    std::set 已订购。所以下面的代码可能会快一点。

    #include <iostream>
    #include <set>
    #include <vector>
    
    typedef std::set<int> Data;
    typedef std::vector<Data> DataSet;
    typedef std::vector<int> Result;
    
    Result findIntersection(const DataSet& sets) {
        Result is; // intersection
        std::vector<Data::iterator> its;
        for (int i = 0; i < sets.size(); ++i) {
            its.push_back(sets[i].begin());
        }
    
        if (its.size() == 0) return is;
        if (its.size() == 1) {
            // return sets[0];
            return is;
        }
    
        while(its[0] != sets[0].end()) {
            const int sentinel = *its[0];
            int counter = 1;
            for (int j = 1; j < its.size(); ++j) {
                while (*its[j] < sentinel && its[j] != sets[j].end()) ++its[j];
                if (its[j] == sets[j].end()) return is;
                if (*its[j] != sentinel) break;
                ++its[j];
                ++counter;
            }
    
            if (counter == its.size()) is.push_back(sentinel);
            ++its[0];
        }
    
        return is;
    }
    
    int main() {
        Data s1{ 1, 2, 3, 4 };
        Data s2{ 2, 4, 5 };
        Data s3{ 2, 4, 7, 8 };
        DataSet data = {s1, s2, s3};
    
        Result is = findIntersection(data);
        std::copy(is.begin(), is.end(), std::ostream_iterator<int>(std::cout, " "));
        return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-13
      • 1970-01-01
      • 1970-01-01
      • 2021-01-03
      相关资源
      最近更新 更多