1. 程式人生 > >華為2015機試--記錄出錯的程式碼所在的檔名稱和行號

華為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尷尬,大家別太。。。重在參觀啊