如何在大型文本文件中对数字进行排序

时间:2017-06-15 14:33:00

标签: c++ sorting

我的任务是对一个大文本文件(> 1GB)进行排序,其中每行排列一个数字,如下例所示:

1906885614
1069046615
1576929003
1690826360
1540261768
786870227
1737467783
295136587
685162468

这是我到目前为止所做的。

#include <iostream>
#include <map>
#include <string>
#include <fstream>
#include <vector>
#include <algorithm>

using namespace std;

int main()
{
    ios_base::sync_with_stdio(false);
    ofstream filtered;
    ofstream filtered1;
    ifstream textfile ("sort_1.txt");
    string text_input;
    map<string, long int> map_data;
    vector<string> sort_vec;
    long int i;

    if (textfile.is_open())
    {
        filtered.open("filtered_list.txt");
        while( ! textfile.eof() )
        {
            getline (textfile, text_input);
            map_data[text_input]++;

            if (map_data[text_input] == 1)
            {
                filtered << text_input << '\n';
            }
        }
        filtered.close();
        textfile.close();
        cout << "Filter Process Complete!" << endl;
        map_data.clear();
    }

    else
        cout << "Unable to Open file: " << endl;

    ifstream textfile1 ("filtered_list.txt");

    if (textfile1.is_open())
    {
        filtered1.open("Filtered_Sorted.txt");
        while( ! textfile1.eof() )
        {
            getline (textfile1, text_input);
            sort_vec.push_back(text_input);
        }
        sort(sort_vec.begin(), sort_vec.end());

        for (i = 0; i < sort_vec.size(); i++)
            filtered1 << sort_vec[i] << endl;
        cout << "Sorting Process Complete!" << endl;
        filtered1.close();
        textfile1.close();
        sort_vec.clear();
    }
    else
        cout << "Unable to Open file: " << endl;

    system("pause");
    return 0;
}

不幸的是,输出似乎不正确。这就是它的样子:

1000107620
1000112250
1000112712
1000113375
1000115080
100011777

等等:

999513319
999515927
999526130
99952947
999531752
999533144
999537

看起来程序忽略了最后的数字,我不知道为什么会发生这种情况。

2 个答案:

答案 0 :(得分:5)

您的输入或输出没有任何问题。该程序正在排序string,并且不会忽略任何字符或数字。 您获得的订单是字母数字。 实际上在以下输入上执行它:

6
55
444
3333
22222
111111

yelds:

111111
22222
3333
444
55
6

这显然是按字母顺序排列的。

要解决问题,您可以

  • make vector<std::string> sort_vec;一个vector<long long> sort_vec; 确保将您从文件中读取的行转换为long long(或使用std::stoll函数转换为您喜欢的任何类型。

以下内容应该有效: sort_vec.push_back(std::stoll(text_input));

  • 另一种选择是使用自定义比较器。这种情况的唯一变化就是您拨打sort
  • 的方式

以下单独应该可以解决问题:

sort(sort_vec.begin(), sort_vec.end(),
     [](auto a, auto b){
        return stoll(a)<stoll(b);
});

正如@Toby Speight所建议的那样,无需将string转换为数字(这样做的一个很好的理由是你不能将数字排序的时间超过long long的最大位数,因为溢出问题。)人们可以简单地比较蜇伤的长度,如果它们相等,则进行字母数字比较(照顾任何前导零)。

sort(sort_vec.begin(), sort_vec.end(),[](auto a, auto b){
    return std::make_tuple(a.length(),a) < std::make_tuple(b.length(),b);
});

我修改了你的代码,我获得的输出是正确的:

输入

6
55
444
3333
22222
111111

输出

6
55
444
3333
22222
111111

这就是你想要的。

答案 1 :(得分:1)

C ++默认按字母顺序排序字符串。字符串"1000115080"按字母顺序排在字符串"100011777"之前,因为字符串中第7个位置的字符'5'按字母顺序排在字符'7'之前。这就是&#34; apple&#34;这个词的原因。在单词&#34; ax&#34;之前排序,即使&#34; ax&#34;人物较少。要将它们排序为整数,请在执行排序之前将字符串转换为整数:

std::vector<long int> sort_vec;
std::string text_input;

while(!textfile.eof()) {
    long int val;
    textfile >> val;
    // do some error checking here.
    sort_vec.push_back(val);
}

sort(sort_vec.begin(), sort_vec.end()); // now this is in numerical order

或将自定义比较功能传递给std::sort

std::vector<std::string> sort_vec;
std::string text_input;

bool comp(std::string a, std::string b) {
    if (a.size() < b.size()) { // numbers with fewer digits are smaller
        return true;
    }
    if (a.size() > b.size()) {
        return false;
    }
    return a < b;
}

while(!textfile.eof()) {
    std::string val;
    std::getline(textfile, val);
    // do some error checking here.
    sort_vec.push_back(val);
}

sort(sort_vec.begin(), sort_vec.end(), comp); // now this is in numerical order, but sort_vec still contains strings rather than ints.

正如评论中所提到的,如果你自己实现选项2(前导零,负号/正号等),你可能会得到错误的答案,所以最好坚持让标准库为你转换为整数