我遗失的边缘在哪里?

时间:2012-12-21 20:43:16

标签: c++ set

我正在尝试使用std::set,我将抛出一堆边,并且只保留唯一的边。

Edge是两个(整数索引)节点之间的一条线。边(1,2)==(2,1),因为这些边是无向的。

但是,我遇到了一个令人费解的情况。在下面代码中标记为//??的部分,行为不符合我的预期。

运行此代码的结果只保留2个边,(1,2)和(4,8)。 (2,1)被集合丢弃,但它不应该,除非我激活//|| ( A==o.B && B==o.A )中注释掉的operator==部分!这里发生了什么?

这个set<Edge>实施让我感到很兴奋。

#include <stdio.h>
#include <set>
using namespace std ;

struct Edge
{
  int A,B ;
  Edge( int iA, int iB ) : A(iA), B(iB) {}
  bool operator==( const Edge & o ) const {
    //??
    return ( A==o.A && B==o.B ) ;//|| ( A==o.B && B==o.A ) ;
  }
  bool operator<( const Edge& o ) const {//MUST BE CONST
    return A < o.A && B < o.B ;
  }
  void print() const { printf( "( %d, %d )", A,B ) ; }
  void compare( const Edge& o ) const {
    print() ;
    if( *this==o ) printf( "==" ) ;
    else printf( "!=" ) ;
    o.print() ;
    puts("");
  }
} ;

int main()
{
  Edge e1( 1, 2 ) ;
  Edge e2( 1, 2 ) ;
  Edge e3( 2, 1 ) ;
  Edge e4( 4, 8 ) ;

  e1.compare( e2 ) ;
  e1.compare( e3 ) ;
  e1.compare( e4 ) ;

  set<Edge> edges ;
  edges.insert( e1 ) ;
  edges.insert( e2 ) ;
  edges.insert( e3 ) ;
  edges.insert( e4 ) ;

  printf( "%d edges\n", edges.size() ) ;
  for( auto edge : edges )
  {
    edge.print();
  }
}

4 个答案:

答案 0 :(得分:5)

C ++ set与==运算符无关,与<运算符无关。您的<运算符会出现问题:如果您希望确保(1,2)等于(2,1),则应更改<的执行情况像这样:

bool operator<( const Edge& o ) const {
    int myMin = min(A, B);
    int myMax = max(A, B);
    int hisMin = min(o.A, o.B);
    int hisMax = max(o.A, o.B);
    return myMin < hisMin || ( myMin == hisMin && myMax < hisMax );
}

这个实现的作用是构造一个边缘的规范表示,其中{A,B}中较小的一个变为“规范A”,而较大的一个变为“规范B”。当以规范形式比较边缘时,(1,2)(2,1)的相等性可以暗示来自(1,2) < (2,1)(2,1) < (1,2)的评估到false

答案 1 :(得分:3)

我认为您的operator<错误,e3<e2e2<e3都是错误的。

也许你想要这样的东西:

return A < o.A || ((A == o.A) && (B < o.B)) ;

答案 2 :(得分:2)

我建议您更改Edge()构造函数,以确保始终初始化A和B,使A<=B(如果边可以指向其原始节点)或A<B(如果不是) ,并放弃在operator ==实现中有额外的逻辑。这对我来说似乎不那么“前卫”了。

答案 3 :(得分:-1)

您的比较应该是

return (A == o.A && B == o.B) || (B == o.A && A == o.B);