2017-11-19 13 views
1

私はカスタムクラスのためにunordered_mapを使用することについていくつかの点を理解しようとしています。私がシンプルなクラスLineを定義するところで、私が運動をするのに使うコードは以下の通りです。私は、Line2main()に挿入すると、なぜの値がLine1Line2の場合には、両方とも3であると、プログラムの出力がinsert failedにならないのは混乱しています。 operator==ファンクションの最初の値(m)のみをclass Lineに比較するので、このコードのLine1Line2は同じキーを持つ必要があるので注意してください。すでに存在しているキーの挿入が無効であってはなりませんか?なぜ私に説明することができますか?ありがとう!カスタムクラスのためのunordered_mapは、同じキーを挿入するときにエラーを起こさない

#include<iostream>                                                                                                           
#include<unordered_map>                                                      

using namespace std;                                                      
class Line {                                                        
public:                                                          
    float m;                                                         
    float c;                                                         

    Line() {m = 0; c = 0;}                                                     
    Line(float mInput, float cInput) {m = mInput; c = cInput;}                                            
    float getM() const {return m;}                                                   
    float getC() const {return c;}                                                   
    void setM(float mInput) {m = mInput;}                                                  
    void setC(float cInput) {c = cInput;}                                                  

    bool operator==(const Line &anotherLine) const                                               
    {                                                          
     return (m == anotherLine.m);                                                   
    }                                                          
};                                                           

namespace std                                                        
{                                                           
    template <>                                                        
    struct hash<Line>                                                       
    {                                                           
    size_t operator()(const Line& k) const                                                 
     {                                                          
     // Compute individual hash values for two data members and combine them using XOR and bit shifting                                 
     return ((hash<float>()(k.getM())^(hash<float>()(k.getC()) << 1)) >> 1);                                       
     }                                                          
    };                                                          
}                                                           

int main()                                                         
{                                                           
    unordered_map<Line, int> t;                                                    

    Line line1 = Line(3.0,4.0);                                                    
    Line line2 = Line(3.0,5.0);                                                    

    t.insert({line1, 1});                                                                                                          
    auto x = t.insert({line2, 2});                                                   
    if (x.second == false)                                                     
    cout << "insert failed" << endl;                                                  

    for(unordered_map<Line, int>::const_iterator it = t.begin(); it != t.end(); it++)                                       
    {                                                           
    Line t = it->first;                                                      
    cout << t.m << " " << t.c << "\n" ;                                                  
    }                                                           

    return 1;                                                         
}  
+2

あなたの演算子==は、衝突時にのみ使用されます。 –

答えて

6

あなたhashoperator ==は、彼らが現在違反一貫性の要件を満たさなければなりません。 ==に従って2つのオブジェクトが等しい場合、そのハッシュコードは、hashに従ってと等しくなければなりません。非同等のオブジェクトが同じハッシュコードを持っているかもしれないが、他の言葉では、同じオブジェクトが同じハッシュコード持っている必要があります。

size_t operator()(const Line& k) const { 
    return hash<float>()(k.getM()); 
} 

をあなたが平等のための一成分のみを比較して、他の成分を無視しているので、あなたがする必要がありますハッシュ関数を変更して、等価性の決定に使用するのと同じコンポーネントを使用します。

+0

あなたの返信ありがとう! unordered_mapの 'insert'関数は、' operator == 'の戻り値をチェックするだけでキーがすでに存在するかどうかを判断してはいけないのは混乱していますか? unordered_mapの 'operator =='やコンパレータの関数についてはあまり明確ではないので、私は間違いをすると思います。もっと説明できますか?ありがとう! –

+2

@ROBOTAI - オブジェクトが空のハッシュスロットで終わった場合、衝突はなく、何も比較する必要はありません。 –

+0

@BoPersson Cool!それが私が逃したポイントです。だから、衝突があった場合、最初に 'insert'がハッシュの衝突をチェックし、次に' operator == 'を使って同等性をチェックします。等しくない場合は、チェーンを使用して衝突を回避します。このことは正しいのでしょうか?ありがとう! –

0

ハッシュで "m"と "c"の両方の値を使用しているため、 "m"と "c"の両方が等しい場合、2つの "Line"インスタンスは同じキーを持ちます。あなたの例の場合。あなたがこれを行うのであれば:

Line line1 = Line(3.0,4.0);                                                    
Line line2 = Line(3.0,4.0);                                                    

t.insert({line1, 1});                                                                                                          
auto x = t.insert({line2, 2});                                                   
if (x.second == false)                                                     
    cout << "insert failed" << endl; 

をあなたはそれが印刷されていることがわかります

0

を「挿入に失敗した」あなたはいつも挿入時にキーを比較するためにカスタム関数を使用することができます。

#include <iostream> 
#include <unordered_map> 

class Line { 
private: 
    float m; 
    float c; 
public: 
    Line() { m = 0; c = 0; } 
    Line(float mInput, float cInput) { m = mInput; c = cInput; } 
    float getM() const { return m; } 
    float getC() const { return c; } 
}; 


struct hash 
{ 
    size_t operator()(const Line& k) const 
    { 
     return ((std::hash<float>()(k.getM())^(std::hash<float>()(k.getC()) << 1)) >> 1); 
    } 
}; 

// custom key comparison 
struct cmpKey 
{ 
    bool operator() (Line const &l1, Line const &l2) const 
    { 
     return l1.getM() == l2.getM(); 
    } 
}; 


int main() 
{ 

    std::unordered_map<Line, int, hash, cmpKey> mymap; // with custom key comparisom 

    Line line1 = Line(3.0, 4.0); 
    Line line2 = Line(4.0, 5.0); 
    Line line3 = Line(4.0, 4.0); 

    auto x = mymap.insert({ line1, 1 }); 
    std::cout << std::boolalpha << "element inserted: " << x.second << std::endl; 
    x = mymap.insert({ line2, 2 }); 
    std::cout << std::boolalpha << "element inserted: " << x.second << std::endl; 
    x = mymap.insert({ line3, 3 }); 
    std::cout << std::boolalpha << "element inserted: " << x.second << std::endl; 

    return 0; 
} 

版画:

element inserted: true 
element inserted: true 
element inserted: false 
関連する問題