2009-10-21 4 views
1

나는 정렬해야하는 앞 부분에 숫자가 들어있는 std :: strings를 가지고있다. 숫자는 정수 또는 실수 일 수 있습니다.소수 정렬 자연 정렬 프로그램을 향상시키는 방법?

정렬이 최적이 아니므로 다음과 같은 자연 정렬 프로그램이 훨씬 좋았습니다. 나는 여전히 숫자가 0보다 작은 작은 문제가 있는데, 바로 정렬하지는 않습니다. 누구든지 개선 할 제안이 있습니까? 우리는 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로 변환 된 문자열로 채워짐) 이것을 float 열로 정렬 한 다음 정렬 된 문자열 열을 출력/사용합니다.

0

데이터가 모두 숫자 인 경우 데이터를 포함 할 새 클래스를 만듭니다.

그것은 데이터를 포함하는 문자열을 가지고 있지만 다음 동작을 모델링하는 더 나은 방법이있을 수 있습니다 - espacially 구현은 또한 정확한을 계산하는 라이브러리의 사용을 포함 할 수있다 운영자에게 <

을 구현하는 데이 경우를 precion 예 GNU multiple precision이 비교가 계정에 숫자의 소수 부분을 가지고 문자열의 비교 및 ​​canversion (또는 숫자가 많은 유효 숫자는 두 배로 사용할 수없는 경우)

2

사용 atof() 대신 atol() 할 것입니다. 반환 유형을 double로 변경해야합니다.

+0

훌륭합니다. – Quadmore

0

값을 한 번 계산하여 저장합니다.
사실 그들은 개체 상태의 일부가 아니기 때문에 (단지 계산 된 값입니다) 변경할 수있는 것으로 표시하십시오. 그런 다음 const 메서드 중에 설정할 수도 있습니다.

또한 MyClass는 자신의 친구이므로 동일한 클래스의 다른 개체의 개인 멤버에 액세스 할 수 있습니다. 따라서 익숙한 접근 자 메서드가 필요하지 않습니다. 접근 자 메소드는 구현중인 클래스가 아닌 구현의 변경으로부터 다른 클래스를 보호한다는 것을 기억하십시오.

atoi()는 정수 만 읽는 것입니다. 즉, '.'문자로 끝납니다. 따라서 0보다 작은 모든 숫자는 비교할 값이 0이므로 임의로 나타납니다 순서대로 부동 소수점 값 (double)으로 추출해야하는 전체 값과 비교하려면

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; 
     } 
};