华为2016年校园招聘上机笔试题(2)----简单错误记录

转载请注明出处<http://blog.csdn.net/qianqin_2014/article/details/51286462>


问题:

开发一个简单错误记录功能小模块,能够记录出错的代码所在的文件名称和行号。

处理:
  1. 记录最多8条错误记录,对相同的错误记录(即文件名称和行号完全匹配)只记录一条,错误计数增加;(文件所在的目录不同,文件名和行号相同也要合并)
  2. 超过16个字符的文件名称,只记录文件的最后有效16个字符;(如果文件名不同,而只是文件名的后16个字符和行号相同,也不要合并)
  3. 输入的文件可能带路径,记录文件名称不能带路径

输入描述:
  1. 一行或多行字符串。每行包括带路径文件名称,行号,以空格隔开。
  2. 文件路径为windows格式
  3. 如:E:\V1R2\product\fpgadrive.c 1325
输出描述:
  1. 将所有的记录统计并将结果输出,格式:文件名代码行数数目,一个空格隔开,如: fpgadrive.c 1325 1 
  2. 结果根据数目从多到少排序,数目相同的情况下,按照输入第一次出现顺序排序。
  3. 如果超过8条记录,则只输出前8条记录.
  4. 如果文件名的长度超过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>

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值