簡體   English   中英

使用自定義比較器的std :: set操作

[英]std::set operations with custom comparator

我有個問題。 當我在自定義比較器中使用std :: set時,其他操作(如擦除或計數)無法正常工作。 例如:

int sz(int const & n) {
  return __builtin_popcount(n);
}

struct comp {
  bool operator()(int const & a, int const & b) const {
    return sz(a) >= sz(b);
  }
};

void solve() {
  set<int, comp> s;

  for (int i = 0; i < 10; ++i)
    s.insert(i);

  for (int x : s)
    cerr << x << " ";

  cerr << "\n";

  for (int i = 0; i < 10; ++i)
    cerr << s.count(i) << " ";
}

輸出將是:

7 9 6 5 3 8 4 2 1 0
0 0 0 0 0 0 0 0 0 0

如何將std :: set與自定義比較器一起使用,以確保所有操作都能正常工作? 提前致謝。

嘗試改變

struct comp {
  bool operator()(int const & a, int const & b) const {
    return sz(a) >= sz(b);
  }
};

struct comp {
  bool operator()(int const & a, int const & b) const {
    return sz(a) > sz(b);
  }  // ---------^ 
};

(第一個)問題是比較器必須施加嚴格的弱排序。

因此,特別是, std::set中的每個a必須為comp(a, a) == false

使用比較器,每個a都有comp(a, a) == true

無論如何:僅當a != b暗示s(a) != s(b) 如果不是這種情況...好吧...我想您可以嘗試

struct comp {
  bool operator()(int const & a, int const & b) const {
    return (sz(a) > sz(b)) || ((sz(a) == sz(b)) && (a > b));
  }
};

或類似的東西。

理論方面的更多內容:

根據std::set的比較器(以及標准庫中所有其他“小於比較器”)的書面要求 ,它需要建立嚴格的弱排序

  • 對於所有acomp(a,a) == false
  • 如果comp(a,b) == truecomp(b,a) == false
  • 如果comp(a,b) == truecomp(b,c) == truecomp(a,c) == true

為了簡短起見,我省略了可比性要求的可傳遞性,該要求由cppreference文檔中的equiv表達式處理,但請注意,以上三個還不夠。

你能想到的比較如要求“必須a前來到b ?” 該實現假定這是比較要問的問題,相等元素的答案是否定的,一個不能出現在另一個之前。 您的比較器未通過前兩個測試:

  • comp(0,0)返回true
  • comp(1,2)返回true ,但是comp(2,1)返回false

這不是任意的。 為了簡單起見,想象一下一個朴素的排序數組。 您有3 1並想插入2 從頭開始,您檢查comp(2,1) 它返回true因為兩者的位數相同,所以您已經完成,現在有了2 3 1 顯然,這是不正確的。 這並不是說std::set與排序數組相同,但是在弄清楚放置和查找元素的位置時需要進行一些操作 嚴格的弱排序使此過程保持一致。

您真正想要的Popcount降序嚴格是大於比較。 因此,更改是微不足道的:

return sz(a) > sz(b);

根據cppreference.com:

一個二進制謂詞,它采用與元素相同類型的兩個參數,並返回布爾值。 如果comp被認為是該類型的對象,而a和b是鍵值,則表達式comp(a,b)如果以函數定義的嚴格弱順序將a認為位於b之前,則返回true。

您的比較器不執行此操作。

暫無
暫無

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

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