2009-10-21 21 views
1

我有std ::字符串包含数字在领导部分,我需要排序。数字可以是整数或浮点数。如何改进小数点的自然排序程序?

vector<std::string>排序不是最佳的,我发现以下自然排序程序更好。数字小于零的问题仍然存在,但排序不正确。有没有人有改善的建议?我们使用Visual Studio 2003.

完整的程序如下。

TIA, 伯特

#include <list> 
#include <string> 
#include <iostream> 

using namespace std; 

class MyData 
{ 
public: 
    string m_str; 
    MyData(string str) { 
     m_str = str; 
    } 

    long field1() const 
    { 
     int second = m_str.find_last_of("-"); 
     int first = m_str.find_last_of("-", second-1); 
     return atol(m_str.substr(first+1, second-first-1).c_str()); 
    } 

    long field2() const 
    { 
     return atol(m_str.substr(m_str.find_last_of("-")+1).c_str()); 
    } 

    bool operator < (const MyData& rhs) 
    { 
     if (field1() < rhs.field1()) { 
      return true; 
     } else if (field1() > rhs.field1()) { 
      return false; 
     } else { 
      return field2() < rhs.field2(); 
     } 
    } 
}; 

int main() 
{ 
    // Create list 
    list<MyData> mylist; 
    mylist.push_front(MyData("93.33")); 
    mylist.push_front(MyData("0.18")); 
    mylist.push_front(MyData("485")); 
    mylist.push_front(MyData("7601")); 
    mylist.push_front(MyData("1001")); 
    mylist.push_front(MyData("0.26")); 
    mylist.push_front(MyData("0.26")); 


    // Sort the list 
    mylist.sort(); 

    // Dump the list to check the result 
    for (list<MyData>::const_iterator elem = mylist.begin(); elem != mylist.end(); ++elem) 
    { 
     cout << (*elem).m_str << endl; 
    } 

    return 1; 
} 

GOT:

0.26 
0.26 
0.18 
93.33 
485 
1001 
7601 

预期:

0.18 
0.26 
0.26 
93.33 
485 
1001 
7601 

回答

1

如果只是浮弦,我宁愿建议创建一个表有两个列(第一行包含原始字符串,第二行填充字符串转换为浮点数) ,按float列对其进行排序,然后输出/使用已排序的字符串列。

0

如果数据都是数字,我会创建一个包含数据的新类。

它可以有一个字符串包括数据,但随后可以让你有更好的方法来模拟行为 - 在这种情况下espacially实现运营商<

的实施也可能包括使用计算到精确库的例如GNU multiple precision这将执行从字符串比较和canversion(或者如果数字不具有许多显著的数字,你可以加倍使用)

2

使用atof(),而不是atol()有比较取数的小数部分考虑进去。您还需要将返回类型更改为双打。

+0

辉煌的,有效的。 – Quadmore 2009-10-21 19:17:00

0

我会计算一次值并存储它们。
因为它们实际上不是对象状态的一部分(它们只是calcualted值),因此将它们标记为可变。然后它们也可以在const方法中设置。

另请注意,MyClass本身就是朋友,因此可以访问同一类的另一个对象的私有成员。所以没有必要使用不寻常的访问器方法。记住Accessor方法是为了保护其他类不受实现中的变化的影响,而不是保证实现的类。

排序的问题在于atoi()只读取整数(即它停在'。'字符处,因此所有小于0的数字都有一个零值用于比较,因此它们会出现在一个随机为了与全值进行比较,需要将它们提取为浮点值(双精度值)。

class MyData 
{ 
private: 
    mutable  bool gotPos; 
    mutable  double f1; 
    mutable  double f2; 
public: 
    /* 
    * Why is this public? 
    */ 
    std::string m_str; 

    MyData(std::string str) 
     :gotPos(false) 
     ,m_str(str)  // Use initializer list 
    { 
     // If you are always going to build f1,f2 then call BuildPos() 
     // here and then you don't need the test in the operator < 
    } 

    bool operator < (const MyData& rhs) 
    { 
     if (!gotPos) 
     { buildPos(); 
     } 
     if (!rhs.gotPos) 
     { rhs.buildPos(); 
     } 
     if (f1 < rhs.f1) return true; 
     if (f1 > rhs.f1) return false; 
     return f2 < rhs.f2; 
    } 
    private: 
     void buildPos() const 
     { 
      int second = m_str.find_last_of("-"); 
      int first = m_str.find_last_of("-", second-1); 

      // Use boost lexical cast as it handles doubles 
      // As well as integers. 
      f1 = boost::lexical_cast<double>(m_str.substr(first + 1, second-first - 1)); 
      f2 = boost::lexical_cast<double>(m_str.substr(second + 1)); 
      gotPos = true; 
     } 
};