天天看點

華為2016年校園招聘上機筆試題(2)----簡單錯誤記錄方法一:使用關聯容器方法二:使用有順序的容器vector

轉載請注明出處<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>

繼續閱讀