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