转载请注明出处<http://blog.csdn.net/qianqin_2014/article/details/51286462>
问题:
开发一个简单错误记录功能小模块,能够记录出错的代码所在的文件名称和行号。
处理:- 记录最多8条错误记录,对相同的错误记录(即文件名称和行号完全匹配)只记录一条,错误计数增加;(文件所在的目录不同,文件名和行号相同也要合并)
- 超过16个字符的文件名称,只记录文件的最后有效16个字符;(如果文件名不同,而只是文件名的后16个字符和行号相同,也不要合并)
- 输入的文件可能带路径,记录文件名称不能带路径
输入描述:
- 一行或多行字符串。每行包括带路径文件名称,行号,以空格隔开。
- 文件路径为windows格式
- 如:E:\V1R2\product\fpgadrive.c 1325
- 将所有的记录统计并将结果输出,格式:文件名代码行数数目,一个空格隔开,如: fpgadrive.c 1325 1
- 结果根据数目从多到少排序,数目相同的情况下,按照输入第一次出现顺序排序。
- 如果超过8条记录,则只输出前8条记录.
- 如果文件名的长度超过16个字符,则只输出后16个字符
输入例子:
E:\V1R2\product\fpgadrive.c 1325
输出例子:
fpgadrive.c 1325 1
方法一:使用关联容器
源代码:
//先将所有的字符串存入哈希表,key为字符串,value为<出现顺序,出现次数>,顺序取相同的字符串的最小值,次数一直累加
//排序的话,利用set重写比较器,按次数降序,次数相同则按出现顺序排列
//插入过程利用hash时间复杂度可以认为是O(n)
//排序过程set的是红黑树,可以认为是O(nlgn) ,总的复杂度就是这个了
#include<iostream>
#include<unordered_map>
#include<set>
#include<string>
#include<utility>
using std::cout;
using std::endl;
using std::cin;
using std::string;
using std::unordered_map;
using std::set;
using std::pair;
struct info{//记录出现的顺序,和次数
int rank;//rank代表出现的顺序
int count;//count代表出现的次数
info(int rank, int count){
this->rank = rank;
this->count = count;
}
};
struct fullinfo{//一条完整的结果,字符串和次数
string file;//记录输入的字符串和行号
int rank;
int count;
fullinfo(string file, int rank, int count){
this->file = file;
this->rank = rank;
this->count = count;
}
};
struct classcomp {//set的比较器
bool operator()(const struct fullinfo& f1, const struct fullinfo& f2){
if (f1.count == f2.count)
return f1.rank<f2.rank;//判断f1出现的顺序是否比f2出现的顺序要早
return f1.count>f2.count;//判断f1出现的次数是否比f2出现的次数要多
}
};
typedef struct info INFO;
typedef struct fullinfo FULLINFO;
int main(){
unordered_map<string, INFO> record;//关键字是字符串和行号,值是该关键字的信息包括出现的顺序和次数
unordered_map<string, INFO>::iterator it;
unordered_map<string, INFO>::const_iterator itfind;
set<FULLINFO, classcomp> ret;//存储处理后的数据,key为字符串、出现的顺序和次数,排序准则用自己定义的结构体
set<FULLINFO, classcomp>::iterator sit;
string linestr;//一行输入
//一条记录是由文件名和行号一起决定的,文件名和行号不用拆分开。
string file;//文件名+行号
int pos;//空格的位置
int i = 1;
while (getline(cin, linestr)){
if (linestr.length() == 0)
break;
pos = linestr.rfind("\\");
file = linestr.substr(pos + 1);//拆分得到最后的filename和count
//const_iterator find(const Key& keyval) const;函数声明
itfind = record.find(file);//在map中查看是否已经有了该字符串,没有则插入,有则次数加1
if (itfind == record.end()){
INFO tmpi(i, 1);
record.insert(pair<string, INFO>(file, tmpi));
}
else{
INFO tmpi(itfind->second.rank, itfind->second.count + 1);
record.erase(file);//删除掉旧的数据,插入新的数据
record.insert(pair<string, INFO>(file, tmpi));
}
i++;
}
for (it = record.begin(); it != record.end(); it++){
FULLINFO tmpfull(it->first, it->second.rank, it->second.count);//构建排序的set集合
ret.insert(tmpfull);
}
/*
文件名和行号之间有空格,找出空格的位置,如果空格的位置小于16,说明空格之前文件名的长度肯定小于16,可以直接输出;
如果空格的位置大于16,那说明文件名长度大于16,找到空格的位置向前移动16位,截断字符串输出,就可以保证只输出文件名的后16位。
*/
for (i = 0, sit = ret.begin(); sit != ret.end() && i<8; ++sit, ++i){//最多输出8条记录,file少于16位
if (file.find(" ") <= 16){
cout << (*sit).file << " " << (*sit).count << endl;
}
else{
cout << (*sit).file.substr(file.find(" ") - 16) << " " << (*sit).count << endl;
}
}
return 0;
}
方法二:使用有顺序的容器vector
#include<iostream>
#include<vector>
#include<string>
#include<cctype>
using std::cout;
using std::endl;
using std::cin;
using std::string;
using std::vector;
using std::swap;
//对字符串中的顺序按条件进行排序
void Process(vector<string> &record, vector<int> &count)
{
int sz = count.size();
for (int i = 0; i < sz; i++)
{
if (1 == count[i])
continue;
else
{
for (int j = 1; j < sz - i; j++)
{
if (count[j - 1] < count[j])
{
swap(count[j-1], count[j]);
swap(record[j-1], record[j]);
}
}
}
}
}
//向字符串容器和计数容器中读取数据
void readLine(vector<string> &record, vector<int> &count, string &str)
{
while (getline(cin, str))
{
if (str.length() == 0)//如果为空串,则输入结束
break;
string lineValid;//输入行中有效的内容,包括文件名和行号
string fileName;//每一行的文件名
auto pos = str.rfind("\\");//获取最后一个转义字符的位置,方便截取输入字符串
lineValid = str.substr(pos + 1);
auto pos2 = lineValid.rfind(" ");//获取空格的位置,方便截取文件名
fileName = lineValid.substr(0, pos2);
if (fileName.length() > 16)//处理文件名,使之小于等于16个字符
{
fileName = fileName.substr(fileName.length() - 16, 16);//处理后的文件名
lineValid = fileName + lineValid.substr(lineValid.find(" "));//处理后的文件名和行号
}
if (record.empty())//如果容器时空的话,也就是第一次输入,要将第一行字符串的有效字符输入到容器中
{
record.push_back(lineValid);
count.push_back(1);
}
else//如果容器不为空,则依次比较该容器中的内容是否和输入的内容相同,若相同,计数器加1,否则,将该数据加入的容器中,相应的计数器要加1
{
int flag = 0;//标志位,判断是否有相同输入行
for (int i = 0; i < record.size(); i++)
{
if (record[i] == lineValid)
{
count[i]++;
flag = 1;
}
}//如果没有与容器中的数据相等的输入,则将该行加入到容器中,并使其计数器加1
if (0 == flag)
{
record.push_back(lineValid);
count.push_back(1);
}
}
}
}
//输出函数
void Print(const vector<string> record, const vector<int> count)
{
int sz = count.size();
if (sz > 8)
sz = 8;
for (int i = 0; i < 8; i++)
cout << record[i] << " " << count[i] << endl;
}
int main()
{
vector<string> record;//记录下所有的有效输入,vector不会出现map中按字典排序的情况,输入的顺序是什么则存储的顺序就是什么
vector<int> count;//记录每行输入的数据出现的次数
string str;//读取每一行输入数据
readLine(record, count, str);
Process(record, count);
Print(record, count);
vector<string>().swap(record);
vector<int>().swap(count);
return 0;
}
转载请注明出处<http://blog.csdn.net/qianqin_2014/article/details/51286462>