本来到软工所是为了做作业和看书的,结果,很不务正业的被一个问题吸引了,这个任务是:从文件中读入一系列格式化好的数据,如
int int int int float float
90900 1442373573 1486014884 0 0.0125 0.0949473
90900 1442373573 1485883012 0 0.0125 0.0945844
90900 836615420 1488523911 2 0.0125 0.00650644
90900 1277583173 1488377356 3 0.0125 0.089611
90900 598391375 1488217313 2 0.0125 0.00790251
90900 1277583173 1306110622 3 0.0125 0.10079
90900 1277583173 1294971886 3 0.0125 0.0947241
然后以某个数据为Key进行查重(一看发现第一排都一样),思路其实相当简单,在输入数据的时候构建Hash表或者树形查找结构(直接使用STL的Set或者Map即可)数据量很大,大约150M以上的数据。 所以其实最大的问题在于怎么做文件操作才可以尽可能快的完成,考虑到150M内存放的下,而传统的一次读取一个数据或者一次一行的操作都要频繁的IO操作,性能必然达不到要求,所以需要一次性将整个文件读入内存,然后再对内存中的格式化数据进行处理。
格式化读入数据我用的是sscanf不知道C++有没其他好的方法,至少我感觉同时使用C++的IO库和C的库是件非常蛋疼的事情,经常会发生各种莫名其妙的错误,还是少用为好。但C++标准的IO库的效率实在是。。。如果不优化绝对满足不了要求的。以前搞ACM的时候的教条,如果你不想TimeOut,那就不要用cin,cout。学学Scanf和Printf吧,少年。记忆尤深啊。
如果内存限制的情况就是尽可能的分割块来求解了,如果仅仅是查重的话,说明重复的数量必然不大,查重的数据结构可以常驻内存。只需要把IO读写的操作考虑清楚就OK了。
在string 的substr上面纠结了很久,因为我的印象中是传入两个参数,一个是开始索引,另一个是结束的。。所以该函数的行为让我很不解,后面一调试发觉不对劲,结果查了下,才发现居然第二个参数是截取的字符数。。。记性不好啊。。确实应该多写才行,string 处理在大三暑假做课程设计时候经常用的,两年多了就忘的差不多了。
不多扯了,代码如下:
#include<vector>
#include <string>
#include <fstream>
#include<iostream>
#include <set>
using namespace std;
//the google data structure
struct Data
{
int Time;
int JobID;
int TaskID;
int JobType;
float NrmlTaskCore;
float NrmlTaskMem;
};
//Store the data into a vector
typedef vector<Data> google_data;
void initData(const string& s_data, google_data& t_data)
{
//cout<<"init"<<endl;
string line;
long index = 0; //记录目前s_data读取的位置
long lineStart;
long fileSize = s_data.size();
Data tmp;
set<int> jobSet;
set<int> taskSet;
index = s_data.find_first_of(char(10), index);
++index;
while(index<=fileSize) //防止溢出
{
lineStart = index;
index = s_data.find_first_of(char(10), index);
if(index==-1) //真正结束循环的地方
break;
//解析string,存为六个字段
line = s_data.substr(lineStart, index-lineStart);
sscanf(line.c_str(), "%d %d %d %d %f %f", &tmp.Time,&tmp.JobID, &tmp.TaskID, &tmp.JobType, &tmp.NrmlTaskCore,&tmp.NrmlTaskMem);
t_data.push_back(tmp);
index +=1;
}
cout<<"The total lines:"<<t_data.size()<<endl;
//遍历解析后的数据,去除重复的jobID和taskID
google_data::iterator itr = t_data.begin();
while(itr != t_data.end())
{
jobSet.insert((*itr).JobID);
taskSet.insert((*itr).TaskID);
itr++;
}
cout<<"The unique jobs :"<<jobSet.size()<<endl;
cout<<"The unique tasks:"<<taskSet.size()<<endl;
}
char * readFile(const char* filename)
{
//cout<<"begin reading..."<<endl;
filebuf *pbuf;
ifstream filestr;
long size;
char *buffer;
//要读入整个文件,必须采用二进制打开
filestr.open(filename, ios::binary);
//获取filestr对应buffer对象的指针
pbuf = filestr.rdbuf();
//调用buffer对象方法获取文件大小
size = pbuf->pubseekoff(0, ios::end, ios::in);
pbuf->pubseekpos(0, ios::in);
//分配内存空间
buffer = new char[size];
//获取文件内容
pbuf->sgetn(buffer, size);
filestr.close();
return buffer;
}
int main()
{
google_data t_data;
//cout<<"read file"<<endl;
char* buf = readFile(".//google-cluster-data-1.csv");
//将读入文件以字符串形式存入fileData中
string fileData(buf);
cout<<"start computing, please wait about more than 1 minutes..."<<endl;
//核心, 处理数据(解析,计算出某个字段的不重复总数)
initData(fileData, t_data);
//cout<<"end of sparse.."<<endl;
// system("pause");
return 0;
}