• 【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;
    }
    
  • 相关阅读:
    电影投票使用到index索引 isdigit range += format upper
    for循环删除列表里的内容 删除字典中的内容
    3.格式化输出 format 三种方法集合% f
    列表和字符串的转换及statswith,endswith的应用判断
    过滤器,使用到in for break
    sort排序及reverse反转的结合使用
    列表内的改动
    django 第五天 自定义标签 静态文件
    Mysql 基础 1
    django 第四天模板渲染
  • 原文地址:https://www.cnblogs.com/dindin1995/p/13059103.html
Copyright © 2020-2023  润新知