簡體   English   中英

為什么與<運算符的矢量比較比較每個項目兩次?

[英]Why does vector comparison with < operator compare each item twice?

在這個例子中,比較兩個向量與<operator result in operator <,在Integer類上定義,為每個元素調用兩次。 但是,將兩個向量與==運算符進行比較時不會發生這種情況。

#include<iostream>
#include<vector>

class Integer {
    public:
        Integer(int value) : m_value(value) {}
        friend bool operator<(const Integer& lhs, const Integer& rhs);
        friend bool operator==(const Integer& lhs, const Integer& rhs);

    private:
        int m_value;

}; 
bool operator<(const Integer& lhs, const Integer& rhs) {
            std::cout << lhs.m_value << " < " << rhs.m_value << '\n';
            return lhs.m_value < rhs.m_value;
}
bool operator==(const Integer& lhs, const Integer& rhs) {
            std::cout << lhs.m_value << " == " << rhs.m_value << '\n';
            return lhs.m_value == rhs.m_value;
}


int main()
{
    std::vector<Integer> ivec1 {1,2,3};
    std::vector<Integer> ivec2 {1,2,3};
    std::cout << (ivec1 < ivec2) << '\n';
    std::cout << (ivec1 == ivec2) << std::endl;
    return 0;
}

此代碼打印:

1 < 1
1 < 1
2 < 2
2 < 2
3 < 3
3 < 3
0
1 == 1
2 == 2
3 == 3
1

為什么會這樣?

如果a < b返回false ,則它不會告訴您b < a ,並且您必須測試它。 那是因為std::vector的逐元素排序對於一對元素a, b可以有三個結果:

  • a < b ,矢量比較返回true
  • b < a ,向量比較返回false
  • 以上兩者都不必測試下一對元素。

所以它必須比較兩個方向。 通過向您的班級添加標識數據,您可以更清楚地看到這一點:

#include<iostream>
#include<vector>

class Integer {
    public:
        Integer(int value, char tag) : m_value(value), m_tag(tag) {}
        friend bool operator<(const Integer& lhs, const Integer& rhs);
        friend bool operator==(const Integer& lhs, const Integer& rhs);

    private:
        int m_value;
        char m_tag;

}; 
bool operator<(const Integer& lhs, const Integer& rhs) {
            std::cout << lhs.m_value << ' ' << lhs.m_tag << " < " << rhs.m_value << ' ' << rhs.m_tag << '\n';
            return lhs.m_value < rhs.m_value;
}
bool operator==(const Integer& lhs, const Integer& rhs) {
            std::cout << lhs.m_value << ' ' << lhs.m_tag << " == " << rhs.m_value << ' ' << rhs.m_tag << '\n';
            return lhs.m_value == rhs.m_value;
}


int main()
{
    std::vector<Integer> ivec1 {{1, 'a'} ,{2, 'a'}, {3, 'a'}};
    std::vector<Integer> ivec2 {{1, 'b'} ,{2, 'b'}, {3, 'b'}};
    std::cout << (ivec1 < ivec2) << '\n';
    std::cout << (ivec1 == ivec2) << std::endl;
    return 0;
}

這會產生:

1 a < 1 b    
1 b < 1 a    
2 a < 2 b    
2 b < 2 a    
3 a < 3 b    
3 b < 3 a    
0    
1 a == 1 b    
2 a == 2 b    
3 a == 3 b    
1

[實例]

為了找到ivec1ivec2的字典順序,該實現尋找ivec1[i] < ivec2[i]ivec2[i] < ivec1[i]的第一個索引i ,因為這將決定順序。

注意如果ivec1[i] < ivec2[i]為假,這需要兩次比較。 特別地,上述情況留下兩種可能性,即“ ivec1[i]ivec2[i]比較等價物”和“ ivec2[i] < ivec1[i] ”。 這個決定是需要進行第二次比較的地方。


一旦找到這樣的索引i ,實現就可以停止比較; 但由於所有條目都比較了您的示例中的等效項,因此必須對每對條目執行兩次比較。

這是因為C ++目前處理比較的設計存在缺陷。 他們正在用修復它; 我不知道它是否會得到vector ,但基本問題將得到解決。

一,問題。

std::vector<基於每個元素< 但是<是一項糟糕的工具。

如果你有兩個元素ab ,要以字面順序排列元組a,b你需要這樣做:

if (self.a < other.a)
  return true;
if (other.a < self.a)
  return false;
return self.b < other.b;

一般來說,這需要2N-1次調用<如果你想要lexographicaly訂購N個元素的集合。

這已經知道了很長時間,這就是為什么strcmp返回一個包含3種值的整數: -1表示less, 0表示相等, +1表示更大(或者,通常,值小於,等於或大於比零)。

有了這個你可以做:

auto val = compare( self.a, other.a );
if (val != 0) return val;
return compare( self.b, other.b );

這需要最多N調用來compare集合中的每個元素。

現在,修復。

添加了太空船比較運算符<=> 它返回一個可以比較大於或小於零的類型,其確切類型通告保證操作提供的內容。

這類似於C的strcmp ,但適用於支持它的任何類型。 此外,有std函數使用<=>如果可用),否則使用<==等來模擬它。

假設向量的要求被重寫為使用<=> ,帶<=>類型將避免雙重比較,並且每次最多只需<=> 'd,以便在調用<時執行std::vector的詞法排序。

暫無
暫無

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

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