2009-10-21 40 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; 
     } 
};