2011-04-26 60 views
7

目前试图排序对象的矢量,其中每个对象包含字符串,在C++重载对比操作者在C++中的结果“无效操作者<”

的字符串可以包含字母或数字(由于设计限制,这是必要的,因为可以改变比较器)。

此刻,对象的类被重载,因此当两个对象进行比较时,它们所包含的字符串将进行比较。这可以起到一定的作用 - 然而,当我使用排序操作(如STL排序)来排列对象时,它会按顺序排序三个字符串,例如“1”,“4”,“12” “1”,“12”,“4”。 4大于12,但由于它从最左边的数字开始比较,所以发生这种“不正确的”排序。

我最初的反应是改变我如何重载比较操作。我会首先检查我正在比较的字符串的长度 - 如果字符串的内容更大或更小,这将是一个指示符号。

// overloaded comparision operators 
friend bool operator<(const nodeRecord & record1, const nodeRecord & record2){ 
    // we need to deal with strings of different lengths... 
    if(record1.comparator.length() < record2.comparator.length()) 
     return true; 
    else 
     return (record1.comparator < record2.comparator); 
} 

此操作在运行时会产生“表达式:无效的运算符<”消息。

有关我在哪里犯错的任何想法?看起来,我应该能够向操作指示我想要如何进行排序操作 - 即使它无效,因为我当前正在使用矢量来包含对象。在nodeRecord对象的初始化过程中

比较:

nodeRecord(int fromNode, int toNode, int connectionCost, bool compareByCost = false){ 
    // take the provided stock information and insert it into the object 
    stringstream fromNodeSS; 
    fromNodeSS << fromNode; 
    this->fromNode = fromNodeSS.str(); 
    stringstream toNodeSS; 
    toNodeSS << toNode; 
    this->toNode = toNodeSS.str(); 
    this->connectionCost = connectionCost; 

    // set the comparator to our chosen comparision term 
    if (!compareByCost){ 
     this->comparator = this->fromNode; // we use from node in this case, since we build the tree outwards 
    } 
    else{ 
     stringstream ss; 
     ss << this->connectionCost; 
     this->comparator = ss.str(); // we use the connection cost in this case, to allow us to sort new connections 
    } 

    // set this as a non-null (active) record 
    this->nullRecord = false; 
} 
+0

有什么比较?发布代码。 – 2011-04-26 05:29:50

+0

你能不能显示比较器的定义? – 2011-04-26 05:45:09

+0

@Mike和@Mario - 比较器在初始化nodeRecord对象期间初始化。你可以看到上面的内容。 – BSchlinker 2011-04-26 05:50:31

回答

10

您的操作员实际上是无效的。

如果您希望它可用于排序,则运算符<必须具有许多数学属性。一个是反对称性质:

x < y => !(y < x)

让我们来定义x = "b"y = "aa"

  • x < y由于"b"长度不如的"aa"
  • y < x"aa"因为长度不如"b"

坎?

另请注意,如果数字的前缀为0 s,那么您的定义很奇怪。

哦,比较字符串比比较数字要慢。

我的拿?停止使用比较信息更改节点。实际的比较模式在节点本身内无关。

然后,您只需编写两种比较方法,一种按成本与另一种按原产地进行比较。


并回到原来的问题,如何编写比较器,考虑["a", "b", "aa"]排序?

你几乎在那里,但“长度”比较是不完整的。只有在长度不同的情况下,您才需要回到实际的词汇比较中,因此您忘记了右侧参数长度低于左侧参数长度的情况。

因此,正确的方式是,假定两个字符串:

bool compare(std::string const& lhs, std::string const& rhs) { 
    if (lhs.length() < rhs.length()) { return true; } 
    if (rhs.length() < lhs.length()) { return false; } // don't forget this 
    return lhs < rhs; 
} 
+0

谢谢!你的解决方案真的帮助我发现并理解问题是什么并提醒我另一个我忘记的案例。 – BSchlinker 2011-04-26 10:09:25

0

你为什么不使用单一的比较和作出这样的功能的小聪明?在开始时检查数字字符,如果是这样,请执行一对strtol()atoi()并比较结果。

否则根据您的非数字要求比较字符串的长度和字符。

+0

我想能够排序字符串,类似于我如何排序数字。例如,叮咬“a”,“aa”和“b”应该被分类为“a”,“b”,“aa”。我发布的方法是我知道的唯一方法,可以让我完成这个任务。 – BSchlinker 2011-04-26 05:52:18

+0

@BSchlinker:更新了我的答案。 – wallyk 2011-04-26 06:02:52

+0

不幸的是,这并不能解决我的问题。同样的错误会发生=( – BSchlinker 2011-04-26 06:04:22

1

发现下面的代码段抛出了错误,然后想到我的重载操作是如何工作的。

template<class _Ty1, class _Ty2> inline 
    bool _Debug_lt(_Ty1& _Left, _Ty2& _Right, 
     _Dbfile_t _File, _Dbline_t _Line) 
    { // test if _Left < _Right and operator< is strict weak ordering 
    if (!(_Left < _Right)) 
     return (false); 
    else if (_Right < _Left) 
     _DEBUG_ERROR2("invalid operator<", _File, _Line); 
    return (true); 
    } 

工作的解决方案是这样的(再次修改这要感谢马修M.留下评论)

// overloaded comparision operators 
friend bool operator<(const nodeRecord & record1, const nodeRecord & record2){ 
    // we need to deal with strings of different lengths... 
    if(record1.comparator.length() > record2.comparator.length() 
     && (record1.comparator.length() !=0 && record2.comparator.length() != 0)) 
     return false; 
    else if(record1.comparator.length() < record2.comparator.length() 
     && (record1.comparator.length() !=0 && record2.comparator.length() != 0)) 
     return true; 
    else 
     return (record1.comparator < record2.comparator); 
} 

谢谢大家谁帮助!