【multimap在文件处理中显奇效】将文本文件的每行内容,按照行首6个数字的升序,重新排序

这是我编程生涯的一块里程碑,作为菜鸟小白,一直在底层仰望程序天空中自由翱翔的前辈们,这次自己起飞了一下下,认识到了数据结构的巨大魅力和无限潜力,感受到了编程带来的快乐!

这里简单记录,以备后续使用。

问题描述

有一份文件,示例如下,前6个字符表示编号,编号应从0-8000左右,但由于某种原因(不重要啦),生成的顺序被打乱,但序号和该行的内容是匹配的。

007453,-1,621,754,1109,927,0.9999844,-1,-1,-1
007453,-1,646,330,1095,522,0.99999344,-1,-1,-1

 
005556,-1,588,681,1004,870,0.9999943,-1,-1,-1
005556,-1,891,166,1222,504,0.99999654,-1,-1,-1

 
007181,-1,1033,130,1259,513,0.99998987,-1,-1,-1
007181,-1,628,593,1056,846,0.9999931,-1,-1,-1

……………………

现在需要按照编号递增的顺序,将每行重新排列。排好后应该是这样的:

000001,-1,607,306,947,518,0.999977,-1,-1,-1
000001,-1,597,700,938,922,0.99997723,-1,-1,-1
000002,-1,608,309,955,519,0.9999672,-1,-1,-1
000002,-1,601,698,919,918,0.99997675,-1,-1,-1
000003,-1,599,302,944,519,0.99996614,-1,-1,-1
000003,-1,603,698,936,920,0.9999789,-1,-1,-1
……………………

待解决的难点:

1、文件读取时,仅使用string读取,句首出现乱码;(使用宽字符串wstring解决)
2、读取文件后,如何减少循环查询的次数。

方法一:暴力解决法

方法一是循环8000次(大约),每次循环过程中,制作该次循环要查找的标准格式号码,每读取到一行非空的内容,取出该行的前6个字符,与制作的号码比较,如果相等说明找到了目标行,把该行和该行下面的行(直到遇到空行)一起写入输出文件。

下面这个程序跑了将近一个小时才出结果:

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <io.h>
#include <codecvt>//读取utf-8文件

using namespace std;

int main()
{
    string fileName = "result.txt";//文件名称

    ofstream out("allout.txt", ofstream::app);//以追加形式写入
    if (!out) {
        cerr << "无法打开输出文件" << endl;
        return -1;
    }

    int j=0;
    
    wstring_convert<std::codecvt_utf8<wchar_t>> conv;
    
    for (int i = 1;i < 8770;++i) {
        //制作应有的名称
        string numstr,nullstring="";
        if (i < 10) numstr = nullstring+"00000" + to_string(i);
        else if(i<100) numstr = nullstring + "0000" + to_string(i);
        else if (i < 1000) numstr = nullstring + "000" + to_string(i);
        else if (i < 10000) numstr = nullstring + "00" + to_string(i);
        wstring wnumstr = conv.from_bytes(numstr);

        string str;
        ifstream in(fileName);
        if (in)//若文件打开成功
        {
            while (getline(in, str))//逐行获取in句柄绑定的文件内容
            {
                wstring wstr = conv.from_bytes(str);
                if (!str.empty() && str != " ") {
                    wstring wstr1(wstr, 0, 6);//获取每行前6个字符
                    
                    if (wnumstr == wstr1) {//找到了首个
                   
                        out << str << endl;
                        getline(in, str);
                        out << str << endl;
                        getline(in, str);
                        if(!str.empty() && str != " ")
                            out << str << endl;
                        break;
                    }
                }
            }
        }
        else {//若文件打开失败
            cerr << "无法打开输入文件" << endl;
            return -1;
        }
    }

    return 0;
}

方法二:巧用multimap

在multimap数据结构的帮助下,一秒出结果!!!

方法二使用multimap<string,string>,第一个string存储非空行的前6个字符(即号码),第二个string存储该行的整行内容。

由于multimap具备自动根据第一个string的字典序排序的能力,所以整个过程只需要一趟循环,便可以将文件中所有的内容存放到multimap中,大约占用800Kb,还是可以接受的, 相当于牺牲空间换时间了。

multimap最具吸引力的就是:只要把数据存好得到的就是排好序的,这是在太高效了!最后再来一趟遍历,输出保存的内容,全程高速!

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <io.h>
#include <codecvt>//读取utf-8文件
#include <map>

using namespace std;

int main()
{
    string fileName = "result.txt";//文件名称

    ofstream out("allout.txt", ofstream::app);//以追加形式写入
    if (!out) {
        cerr << "无法打开输出文件" << endl;
        return -1;
    }

    wstring_convert<std::codecvt_utf8<wchar_t>> conv;//用于wstring和string的转换
    multimap<string, string> mymultimap;//应取得C位!!!

    string str;
    ifstream in(fileName);
    if (in)//若文件打开成功
    {
        while (getline(in, str))//逐行获取in句柄绑定的文件内容
        {
            wstring wstr = conv.from_bytes(str);
            if (!str.empty() && str != " ") {
                wstring wstr1(wstr, 0, 6);//获取每行前6个字符
                string str1 = conv.to_bytes(wstr1);
                auto ret = mymultimap.insert({ str1,str });//将<前缀,该行内容>存入map
            }
        }
        //遍历multimap,将内容输出到文件
        for (auto i : mymultimap) {
            out << i.second << endl;
        }
    }
    else {//若文件打开失败
        cerr << "无法打开输入文件" << endl;
        return -1;
    }

    return 0;
}

posted on 2020-04-23 14:22  丁错儿  阅读(5)  评论(0编辑  收藏  举报

导航