華為2015機試--記錄出錯的程式碼所在的檔名稱和行號
我沒機會參加今年華為的提前招聘(都不知道有這個渠道)題目如下:
開發一個簡單錯誤記錄功能小模組,能夠記錄出錯的程式碼坐在的檔名稱和行號。
處理:
1.記錄最多8條錯誤記錄,對相同的錯誤記錄(即檔名稱和行號完全匹配)只記錄一條,錯誤計數增加;
(檔案所在的目錄不同,檔名和行號相同也要合併)
2.超過16個字元的檔名稱,只記錄檔案的最後有效16個字元;(如果檔名不同,而只是檔名的後16個字元和行號相同,也不要合併)
3.輸入的檔案可能帶路徑,記錄檔名稱不能帶路徑
輸入描述:
一行或多行字串。每行包括帶路徑檔名稱,行號,以空格隔開。
檔案路徑為windows格式
如:E:\V1R2\product\fpgadrive.c 1325
輸出描述:
將所有的記錄統計並將結果輸出,格式:檔名程式碼行數數目,一個空格隔開,如: fpgadrive.c 1325 1
結果根據數目從多到少排序,數目相同的情況下,按照輸入第一次出現順序排序。
如果超過8條記錄,則只輸出前8條記錄.
如果檔名的長度超過16個字元,則只輸出後16個字元
題目本身看起來不難,但動手做起來還是花了幾個小時才弄出來,在某網測試超時啦(汗,我好菜),下面貼出我的實現程式碼,本著練習C/C++的心態,使用了C++的非標準容器hash_map,標準容器string,multimap,字串流stringstream(很喜歡這個類,一些型別轉換成字串或字串轉其他型別不要太方便,比什麼itoa,sprintf,sscanf之流方便多了)以及函式物件,還有C的字串處理函式等。雖然用了這麼多工具 ,但沒什麼用,測試說超時了(100個測試用例,花了6、7秒鐘),但結果是正確的,在這裡寫成部落格,只要是總結經驗,留給將來自己複習,而分享給大家,是給大家一個參照吧。上程式碼。。。
#include <iostream> #include <sstream> #include <string> #include <cstring> #include <hash_map> #include <map> #include <functional> using namespace std; using namespace __gnu_cxx; class errorItem{ public: errorItem() {}; errorItem(int index, int num, const char* fileName, int nCount = 1) { _index = index; _num = num; strcpy(_fileName, fileName); _nCount = nCount; } errorItem(const errorItem& eItem) { _index = eItem._index; _num = eItem._num; _nCount = eItem._nCount; strcpy(_fileName, eItem._fileName); } public: int _index; //記錄行輸入的順序號 int _num; //行號 char _fileName[17]; //檔名 ,長度不超過16字元 int _nCount; //該記錄的重複次數 }; struct Idx{ int nCount; int index; }; struct Comp{ bool operator()(const Idx& idx1, const Idx& idx2)const { if(idx1.nCount == idx2.nCount) return idx1.index < idx2.index ? true:false; else return idx1.nCount > idx2.nCount ? true:false; } }; struct eqStr{ bool operator() (const string& str1, const string& str2) const{ return str1 == str2; } }; struct str_hash{ size_t operator()(const string& str) const { unsigned long __h = 0; for (size_t i = 0 ; i < str.size() ; i ++) __h = 65535*__h + str[i]; return size_t(__h); } }; int main() { int index = 0; string errorStr; hash_map<string, errorItem, str_hash, eqStr> hashMap; multimap<Idx, string, Comp> itemsMap; while(getline(cin, errorStr)){ ++index; string keyStr, fileName, numStr; char ftFileName[17] = {'\0'}; string::size_type idx1 = errorStr.find_last_of('\\'); string::size_type idx2 = errorStr.find_last_of(' '); if(idx2 == string::npos) continue; if(idx1 == string::npos){ keyStr = errorStr.substr(0); fileName = errorStr.substr(0, idx2-1); } else{ keyStr = errorStr.substr(idx1+1); fileName = errorStr.substr(idx1+1, idx2-idx1-1); } numStr = errorStr.substr(idx2+1); int num = atoi(numStr.c_str()); int fileNameLen = fileName.length(); if(fileNameLen > 16){ //檔名長度大於16,取最後16個有效字元 string::size_type st = 0; string::size_type st16 = st; while(st != string::npos){ if(st >= 16) st16 = st16 + 1; st = st + 1; } strcpy(ftFileName, fileName.substr(st16).c_str()); } else strcpy(ftFileName, fileName.c_str()); if(hashMap.count(keyStr) < 1) hashMap.insert(make_pair(keyStr, errorItem(index, num, ftFileName))); else hashMap[keyStr]._nCount++; } typedef hash_map<string, errorItem, str_hash, eqStr>::iterator hashIter; //cout << hashMap.size() << endl; for(hashIter iter = hashMap.begin(); iter != hashMap.end(); ++iter){ ostringstream is; is << iter->second._fileName << " " << iter->second._num << " " << iter->second._nCount; string retStr = is.str(); Idx newIdx = {iter->second._nCount, iter->second._index}; itemsMap.insert(make_pair(newIdx, retStr)); } typedef multimap<Idx, string, Comp>::iterator mulIter; int i = 1; for(mulIter iter = itemsMap.begin(); i <= 8 && iter != itemsMap.end(); ++i,++iter) { //cout << iter->first.nCount << " " << iter->first.index << " "; cout << iter->second << endl; } return 0; }
先總結上面程式碼中非標準容器hash_map的使用過程中,需要注意的地方,上面程式碼是在codeblock上的gcc編譯的。
a、需要引用標頭檔案#include <hash_map>
b、需要引用名稱空間:using namespace __gnu_cxx;
c、定義hash_map物件時,按照你設定的key型別,若不是預設型別,需要重新定義hash函式、equal_to函式.對於值型別,若是自定義型別,該自定義型別的類中必須有拷貝建構函式、顯示的無參建構函式,原因看hash_map原始碼可知,hash_map成員函式會呼叫值型別的拷貝建構函式和無參建構函式,具體可看hash_map的原始碼。
hash_map原型是:
template hash_map< class key, class T, class HashFcn = hash<key>, class EqualKey = equal_to<key>, class Alloc = alloc>
class hash_map { ..... };
C++標準中預設定義的hash函式的型別包括:char, int, long, char*, const char*, unsigned char, signed char, short, unsigned short, unsigned int , unsigned long,它們定義在<stl_hash_fun.h>中,有興趣可以看看其中實現。所以對於string型別的key,就需要自己重新定義hash啦,不難。
自己定義string型別hash函式物件:
struct str_hash{
size_t operator()(const string& str) const
{
unsigned long __h = 0;
for (size_t i = 0 ; i < str.size() ; i ++)
__h = 65535*__h + str[i];
return size_t(__h);
}
};
或者呼叫現成的,注意要引用<stl_hash_fun.h>
struct str_hash{
size_t operator()(const string& str) const
{
return (size_t)__stl_hash_string(str.c_str());
}
}
對於值型別,若是自定義的,你也必須重新定義equal_to,自定義成函式物件
struct eqStr{
bool operator() (const string& str1, const string& str2) const{
return str1 == str2;
}
};
最後說下我測試的100條資料,執行結果吧:
測試資料:
e:\1\aa3.txt 3
e:\3\aa1.txt 2
e:\2\aa2.txt 3
e:\3\aa1.txt 1
e:\1\aa1.txt 3
e:\3\aa1.txt 2
e:\1\aa3.txt 3
e:\2\aa3.txt 2
e:\1\aa1.txt 2
e:\3\aa3.txt 2
e:\1\aa2.txt 2
e:\1\aa3.txt 1
e:\1\aa3.txt 1
e:\2\aa3.txt 2
e:\1\aa2.txt 1
e:\3\aa1.txt 2
e:\1\aa1.txt 3
e:\2\aa1.txt 1
e:\3\aa3.txt 2
e:\1\aa1.txt 1
e:\2\aa2.txt 2
e:\3\aa3.txt 2
e:\1\aa2.txt 1
e:\1\aa3.txt 2
e:\1\aa3.txt 3
e:\1\aa2.txt 3
e:\3\aa1.txt 3
e:\2\aa2.txt 2
e:\1\aa1.txt 1
e:\2\aa3.txt 1
e:\3\aa1.txt 1
e:\2\aa1.txt 3
e:\3\aa3.txt 2
e:\1\aa3.txt 3
e:\2\aa3.txt 3
e:\1\aa2.txt 3
e:\2\aa2.txt 1
e:\1\aa3.txt 1
e:\1\aa3.txt 1
e:\3\aa3.txt 3
e:\3\aa3.txt 2
e:\1\aa2.txt 3
e:\1\aa2.txt 3
e:\1\aa2.txt 3
e:\1\aa1.txt 1
e:\2\aa3.txt 1
e:\3\aa3.txt 1
e:\2\aa3.txt 2
e:\3\aa1.txt 3
e:\2\aa2.txt 2
e:\2\aa2.txt 2
e:\2\aa3.txt 1
e:\1\aa3.txt 3
e:\3\aa1.txt 2
e:\3\aa2.txt 2
e:\1\aa2.txt 1
e:\2\aa2.txt 1
e:\2\aa1.txt 2
e:\2\aa2.txt 1
e:\1\aa2.txt 1
e:\2\aa3.txt 1
e:\2\aa2.txt 1
e:\2\aa1.txt 2
e:\3\aa2.txt 3
e:\3\aa1.txt 3
e:\2\aa2.txt 3
e:\2\aa3.txt 1
e:\3\aa3.txt 2
e:\2\aa3.txt 1
e:\1\aa1.txt 2
e:\3\aa3.txt 1
e:\3\aa1.txt 1
e:\2\aa2.txt 3
e:\3\aa3.txt 2
e:\2\aa1.txt 3
e:\1\aa3.txt 3
e:\3\aa2.txt 1
e:\2\aa1.txt 3
e:\1\aa3.txt 3
e:\2\aa2.txt 2
e:\1\aa1.txt 2
e:\3\aa1.txt 1
e:\1\aa3.txt 1
e:\3\aa1.txt 2
e:\1\aa1.txt 2
e:\1\aa1.txt 3
e:\3\aa1.txt 1
e:\3\aa1.txt 1
e:\2\aa3.txt 3
e:\2\aa2.txt 1
e:\2\aa1.txt 2
e:\2\aa2.txt 1
e:\3\aa2.txt 3
e:\1\aa2.txt 1
e:\3\aa2.txt 2
e:\2\aa1.txt 1
e:\2\aa3.txt 3
e:\1\aa1.txt 2
e:\1\aa1.txt 1
e:\1\aa1.txt 2
測試結果如下:
。。。這次竟然10s,大家別太。。。重在參觀啊