簡體   English   中英

使用自定義哈希函數插入unordered_set

[英]Inserting into an unordered_set with custom hash function

我有以下代碼來制作unordered_set<Interval> 編譯好了。

struct Interval {
  unsigned int begin;
  unsigned int end;
  bool updated;   //true if concat.  initially false
  int patternIndex;  //pattern index. valid for single pattern
  int proteinIndex;   //protein index.  for retrieving the pattern
};

struct Hash {
  size_t operator()(const Interval &interval);
};

size_t Hash::operator()(const Interval &interval){
  string temp = to_string(interval.begin) + to_string(interval.end) + to_string(interval.proteinIndex);
  return hash<string>()(temp);
}

unordered_set<Interval, string, Hash> test;

但是,當我嘗試使用此代碼插入時,我無法編譯:

for(list<Interval>::iterator i = concat.begin(); i != concat.end(); ++i){
  test.insert((*i));
}

而且,我無法確定錯誤消息的問題,例如:

note: candidate is:
note: size_t Hash::operator()(const Interval&)
note:   candidate expects 1 argument, 2 provided  

我以為我只提供了一個論點......

我的插入代碼有什么問題?


這是新的實例化代碼: unordered_set<Interval, Hash> test; 但是,我仍然收到大量錯誤消息,例如:

note: candidate is:
note: size_t Hash::operator()(const Interval&) <near match>
note:   no known conversion for implicit ‘this’ parameter from ‘const Hash*’ to ‘Hash*’

第一個問題:

您正在傳遞string作為實例化unordered_set<>類模板的第二個模板參數。 第二個參數應該是hasher仿函數的類型 ,而std::string不是可調用對象。

或許打算寫:

unordered_set<Interval, /* string */ Hash> test;
//                      ^^^^^^^^^^^^
//                      Why this?

另外,我建議使用beginend以外的名稱作為(成員)變量,因為這些是C ++標准庫的算法名稱。

第二個問題:

你應該記住, hasher函數應該被限定為const ,所以你的函子應該是:

struct Hash {
   size_t operator() (const Interval &interval) const {
   //                                           ^^^^^
   //                                           Don't forget this!
     string temp = to_string(interval.b) + 
                   to_string(interval.e) + 
                   to_string(interval.proteinIndex);
     return (temp.length());
   }
};

第三個問題:

最后,如果您希望std::unordered_set能夠使用Interval類型的對象,則需要定義與哈希函數一致的相等運算符。 默認情況下,如果未指定任何類型參數作為std::unordered_set類模板的第三個參數,則將使用operator ==

您目前沒有為您的類Interval重載operator == ,因此您應該提供一個。 例如:

inline bool operator == (Interval const& lhs, Interval const& rhs)
{
    return (lhs.b == rhs.b) && 
           (lhs.e == rhs.e) && 
           (lhs.proteinIndex == rhs.proteinIndex); 
}

結論:

完成上述所有修改后,您可以在此實例中看到您的代碼編譯。

我認為,Andy Prowl完美地解決了代碼中存在的問題 但是,我會在Interval添加以下成員函數,它描述了兩個區間相同的原因:

std::string getID() const { return std::to_string(b) + " " + std::to_string(e) + " " + std::to_string(proteinIndex); }

請注意,我也跟着安迪四處尋覓的建議,並改名為成員beginb ,並ende 接下來,您可以使用lambda表達式輕松定義哈希和比較函數。 因此,您可以按如下方式定義unordered_set

auto hash = [](const Interval& i){ return std::hash<std::string>()(i.getID()); };
auto equal = [](const Interval& i1, const Interval& i2){ return i1.getID() == i2.getID(); };
std::unordered_set<Interval, decltype(hash), decltype(equal)> test(8, hash, equal);

最后,出於可讀性的原因,我將for循環轉換for基於范圍的for循環:

std::list<Interval> concat {{1, 2, false, 3, 4}, {2, 3, false, 4, 5}, {1, 2, true, 7, 4}};

for (auto const &i : concat)
    test.insert(i);

for (auto const &i : test)
    std::cout << i.b << ", " << i.e << ", " << i.updated << std::endl;

輸出(我剛剛打印了每個Interval前三個成員):

2,3,0
1,2,0

如您所見,只打印了兩個間隔。 第三個( {1, 2, true, 7, 4} proteinIndex {1, 2, true, 7, 4} )沒有插入到concat ,因為它的beproteinIndex等於第一個區間的值( {1, 2, false, 3, 4} )。

Ideone上的代碼

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM