如何改进小数的自然排序程序?

时间:2009-10-21 18:35:42

标签: c++ sorting

我有std :: strings包含我需要排序的前导部分中的数字。数字可以是整数或浮点数。

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

4 个答案:

答案 0 :(得分:2)

使用atof()代替atol()进行比较,将数字的小数部分考虑在内。您还需要将返回类型更改为双精度。

答案 1 :(得分:1)

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

答案 2 :(得分:0)

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

它可以有一个字符串来包含数据,但随后允许您有更好的方法来建模行为 - 在这种情况下,特别是为了实现运算符&lt;

该实现还可以包括使用计算精确值的库,例如GNU multiple precision这会从字符串进行比较和反转(或者如果数字没有那么多可以使用双重数字的重要数字)

答案 3 :(得分:0)

我会计算一次值并存储它们 因为它们实际上不是对象状态的一部分(它们只是计算值),所以将它们标记为可变。然后它们也可以在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;
        }
};