【问题标题】:Unordered selection implementation based on std::set ends up having duplicates基于 std::set 的无序选择实现最终有重复
【发布时间】:2020-03-17 15:26:41
【问题描述】:

尝试在不考虑 std::set 容器的对象的排列(必须将其视为重复项:因此顺序不重要)的情况下实现 4 个对象的组合,一次取 2 个对象:

struct Combination {
    int m;
    int n;
    Combination(const int m, const int n):m(m),n(n){}
};
const auto operator<(const auto & a, const auto & b) {
    //explicitly "telling" that order should not matter:
    if ( a.m == b.n && a.n == b.m ) return false;
    //the case "a.m == b.m && a.n == b.n" will result in false here too:
    return a.m == b.m ? a.n < b.n : a.m < b.m;
}
#include <set>
#include <iostream>
int main() {
    std::set< Combination > c;
    for ( short m = 0; m < 4; ++ m ) {
    for ( short n = 0; n < 4; ++ n ) {
        if ( n == m ) continue;
        c.emplace( m, n );
    } }
    std::cout << c.size() << std::endl; //12 (but must be 6)
}

预期的组合集是0 10 20 31 21 32 3,这是其中的 6 个,但结果是 c.size() == 12。另外,我的operator&lt;(Combination,Combination) 确实满足!comp(a, b) &amp;&amp; !comp(b, a) means elements are equal 的要求。

我错过了什么?

【问题讨论】:

    标签: c++ set stdset


    【解决方案1】:

    您的代码无法运行1,因为您的 operator&lt; 没有引入严格的总排序。严格总排序的一项要求是,对于任意三个元素 abc

    a < b
    

    b < c
    

    暗示

    a < c
    

    (在数学意义上)。让我们检查一下。如果我们采取

    Combination a(1, 3);
    Combination b(1, 4);
    Combination c(3, 1);
    

    你看到了

    a < b => true
    b < c => true
    

    但是

    a < c => false
    

    如果你不能订购你不能使用的元素std::setstd::unordered_set 似乎更适合这项任务。您只需要一个 operator== 来比较相等性,这是微不足道的,以及一个哈希函数,它为被认为相同的元素返回相同的值。就像添加mn 一样简单。


    1 好吧,也许它可以工作,或不工作,或两者兼而有之,这是未定义的行为。

    【讨论】:

    • 谢谢,它解释了很多。你怎么知道呢? std 文档中是否有任何说明?找不到herehere
    • 是的,here(第一段,第二句)(有点隐藏)表示“使用键比较函数比较完成排序。”here您可以找到比较的要求(comp(a, b)
    • 确实,错过了:if comp(a,b)==true and comp(b,c)==true then comp(a,c)==true,感谢您指出这一点。
    【解决方案2】:

    附件是工作代码。您缺少的棘手部分是没有添加一段代码来遍历已经工作的集合然后检查值。你很亲近!如果您需要更全面的答案,我将在 cmets 中回答问题。希望这会有所帮助!

    #include <set>
    #include <iostream>
    
    
    using namespace std; 
    
    struct Combination {
        int m;
        int n;
        Combination(const int m, const int n):m(m),n(n){}
    };
    const auto operator<(const auto & a, const auto & b) {
        //explicitly "telling" that order should not matter:
        if ( a.m == b.n && a.n == b.m ) return false;
        //the case "a.m == b.m && a.n == b.n" will result in false here too:
        return a.m == b.m ? a.n < b.n : a.m < b.m;
    }
    
    
    int main() {
        set< Combination > c;
        for ( short m = 0; m < 4; ++ m ) 
        {
             for ( short n = 0; n < 4; ++ n ) 
              { 
                    //Values are the same we do not add to the set
                    if(m == n){
    
                        continue; 
                    }
                    else{
                       Combination s(n,m);  
    
                       const bool is_in = c.find(s) != c.end();
                       if(is_in == true){
    
                           continue; 
                       }
                       else{
                           cout << " M: " << m << " N: " << n << endl; 
                           c.emplace( m, n); 
                       }
    
                    }
              } 
        }
    
        cout << c.size() << endl; //16 (but must be 6)
    
    
    }
    

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-19
    • 2015-05-21
    • 2022-08-18
    • 2012-07-26
    • 2013-04-02
    • 1970-01-01
    • 1970-01-01
    • 2014-03-15
    相关资源
    最近更新 更多