[DS][Hash][PAT][电话聊天狂人]

来源:互联网 发布:kdl55w800b安装软件 编辑:程序博客网 时间:2024/04/30 07:58
11-散列1 电话聊天狂人   (25分)

给定大量手机用户通话记录,找出其中通话次数最多的聊天狂人。

输入格式:

输入首先给出正整数N105),为通话记录条数。随后N行,每行给出一条通话记录。简单起见,这里只列出拨出方和接收方的11位数字构成的手机号码,其中以空格分隔。

输出格式:

在一行中给出聊天狂人的手机号码及其通话次数,其间以空格分隔。如果这样的人不唯一,则输出狂人中最小的号码及其通话次数,并且附加给出并列狂人的人数。

输入样例:

413005711862 1358862583213505711862 1308862583213588625832 1808792583215005713862 13588625832

输出样例:

13588625832 3



>>>
这个题自己先尝试这做了一遍,不知道为什么,测试用例3过不去(边界测试,最大N)
代码如下:
#include <iostream>#include <string>using namespace std;typedef int Index;typedef string ElementType;typedef struct ListNode *Position;typedef Position List;struct ListNode {ElementType PhoneNum;int cnt;Position Next;};struct HashTbl {List *TheLists;int TableSize;};typedef struct HashTbl *HashTable;int NextPrime(int x);HashTable InitializeTable(int TableSize);void DestroyTable(HashTable H);void Insert(ElementType Key, HashTable H);Position Find(ElementType Key, HashTable H);Index Hash(ElementType Key, int TableSize);Position FindMax(HashTable H, int &maxSame);Position MAXP;int MAXSAME = 1;int MAXCNT = 0;int main(){HashTable H;int N, maxSame = 1;ElementType send, rec;Position maxP;cin >> N;H = InitializeTable(2*N);for (int i = 0; i != N; ++i) {cin >> send >> rec;//cout << send << " " << rec << endl;Insert(send, H);Insert(rec, H);}//cout << Find("13588625832", H)->cnt << endl;//debugcout << MAXP->PhoneNum << " " << MAXP->cnt;if (1 != MAXSAME) {cout << " " << MAXSAME;}cout << endl;//maxP = FindMax(H, maxSame);//cout << maxP->PhoneNum << " " << maxP->cnt;//if (1 != maxSame) {//cout << " " << maxSame;//}//cout << endl;DestroyTable(H);}int NextPrime(int x){for (int Next = x;; ++Next) {int i;for (i = 2; i * i <= Next; ++i) {if (Next % i == 0) break;}if (i * i > Next) {return Next;}}}//HashTable : Separate ChainingHashTable InitializeTable(int TableSize){HashTable H;H = new HashTbl;H->TableSize = NextPrime(TableSize);H->TheLists = new List[H->TableSize];for (int i = 0; i != H->TableSize; ++i) {H->TheLists[i] = new ListNode;H->TheLists[i]->Next = nullptr;}return H;}void DestroyTable(HashTable H){for (int i = 0; i != H->TableSize; ++i) {delete H->TheLists[i];}delete[]H->TheLists;delete H;}Position Find(ElementType Key, HashTable H){Position P;List L;L = H->TheLists[Hash(Key, H->TableSize)];P = L->Next;while (P != nullptr && P->PhoneNum != Key) {P = P->Next;}return P;}void Insert(ElementType Key, HashTable H){Position Pos, NewCell;List L;Pos = Find(Key, H);if (nullptr == Pos) {NewCell = new ListNode;L = H->TheLists[Hash(Key, H->TableSize)];NewCell->Next = L->Next;NewCell->PhoneNum = Key;NewCell->cnt = 1;L->Next = NewCell;} else {++(Pos->cnt);if (Pos->cnt > MAXCNT) {MAXCNT = Pos->cnt;MAXP = Pos;MAXSAME = 1;} else if (Pos->cnt == MAXP->cnt) {if (Pos->PhoneNum < MAXP->PhoneNum) {MAXP = Pos;}++MAXSAME;}}}Index Hash(ElementType Key, int TableSize){unsigned int HashVal = 0;//int i = 0;//while (Key[i] != '\0') {//HashVal += Key[i++]-'0';//}HashVal = atoi(&Key[6]);return HashVal % TableSize;}Position FindMax(HashTable H, int &maxSame){Position P, maxP = H->TheLists[0]->Next;int maxCnt = 0;maxSame = 1;for (int i = 0; i != H->TableSize; ++i) {P = H->TheLists[i]->Next;while (P != nullptr) {if (P->cnt > maxCnt) {maxP = P;maxCnt = P->cnt;maxSame = 1;} else if (P->cnt == maxCnt) {if (P->PhoneNum < maxP->PhoneNum) {maxP = P;}++maxSame;}P = P->Next;}}return maxP;}

想法:
解决冲突的方法:分离连接法

最初我写了一个函数FindMax,在创建好哈希表之后用FindMax遍历一次哈希表找出cnt最大的结点,如果有多个cnt并列,保证该结点电话号最小,也统计了具有相同cnt的人数。
因为测例3超时,我觉得遍历也会花时间,就改成了在创建哈希表的时候就找出cnt最大的结点。所以创建了三个全局变量MAXP,MAXCNT,MAXSAME来模仿FindMax。思路很简单,看FindMax应该可以直接看懂,就是比较。
同时,突然意识到自己的Hash函数可能有问题,改成了用 手机号的后5位%TableSize 作为Hash函数。
结果还超时!就不知道为什么了。于是看浙大数据结构MOOC配套的实验指导书,笔记与想法如下:

1. 为了更有效率地设计散列表,需要仔细分析手机号码各个位的特点。
2. 由于本题不涉及删除,所以采用了简化版散列表定义及初始化。
3. 注意到11位手机号已经超出了长整型范围,所以应将其存为字符串。(这个我之前也发现了,只能存为long long才不会超出范围,所以用string来保存手机号)


结果发现自己的解决思路和实验指导书上的几乎一样,实在不知道性能瓶颈在哪里!!!


统计了一下程序运行时间,发现问题集中在创建哈希表这里,而不是FindMax有问题:
int main(){HashTable H;int N, maxSame = 1;ElementType send, rec;start = clock();cin >> N;H = InitializeTable(2*N);for (int i = 0; i != N; ++i) {cin >> send >> rec;Insert(send, H);Insert(rec, H);}stop = clock();duration = ((double)(stop - start)) / CLK_TCK;cout << duration << endl;start = clock();FindMax(H);stop = clock();duration = ((double)(stop - start)) / CLK_TCK;cout << duration << endl;DestroyTable(H);}

结果如下:
3.474
13509006138 6 3
0.011

这个是测试用例3的运行结果(我安装了PAT的离线版本,里面有测试用例以及这个题的c语言解答,自带的答案运行不超时)
我的时间是自带答案的10倍!

改进1:Insert中避免两次调用Hash()
取消Insert()中的Find(), 直接替换称Find函数体。这样避免了两次调用Hash函数。略有改进,变为2.5s左右
改进2:Hash函数改变参数
Hash(string Key,..)改为Hash(int Key,..),将传递的参数有string改为atoi(&Key[6])。略有改进,变为2.22s左右
改进3:string和new会不会是性能瓶颈?
我去!问题果然在这里!!!!!!!!!!!!!
做算法题最好用char *不要用string!!!!!!!!
提交后完美通过,代码如下:

// improve 1, 2//#include <iostream>//#include <string>//#include <cstdlib> //atoi//#include <ctime>//clock_t start, stop;//double duration;////using namespace std;////typedef int Index;//typedef string ElementType;//typedef struct ListNode *Position;//typedef Position List;//struct ListNode {//ElementType PhoneNum;//int cnt;//Position Next;//};//struct HashTbl {//List *TheLists;//int TableSize;//};//typedef struct HashTbl *HashTable;////int NextPrime(int x);//HashTable InitializeTable(int TableSize);//void DestroyTable(HashTable H);//void Insert(ElementType Key, HashTable H);//Position Find(ElementType Key, HashTable H);//Index Hash(int Key, int TableSize);//void FindMax(HashTable H);////int main()//{//HashTable H;//int N, maxSame = 1;//ElementType send, rec;////start = clock();////cin >> N;//H = InitializeTable(2*N);////stop = clock();//duration = ((double)(stop - start)) / CLK_TCK;//cout << duration << endl;////start = clock();//for (int i = 0; i != N; ++i) {//cin >> send >> rec;//Insert(send, H);//Insert(rec, H);//}////stop = clock();//duration = ((double)(stop - start)) / CLK_TCK;//cout << duration << endl;////start = clock();////FindMax(H);////stop = clock();//duration = ((double)(stop - start)) / CLK_TCK;//cout << duration << endl;////DestroyTable(H);//}////int NextPrime(int x)//{//for (int Next = x;; ++Next) {//int i;//for (i = 2; i * i <= Next; ++i) {//if (Next % i == 0) break;//}//if (i * i > Next) {//return Next;//}//}//}////HashTable : Separate Chaining//HashTable InitializeTable(int TableSize)//{//HashTable H;//H = new HashTbl;//H->TableSize = NextPrime(TableSize);//H->TheLists = new List[H->TableSize];//for (int i = 0; i != H->TableSize; ++i) {//H->TheLists[i] = new ListNode;//H->TheLists[i]->Next = nullptr;//}//return H;//}////void DestroyTable(HashTable H)//{//for (int i = 0; i != H->TableSize; ++i) {//delete H->TheLists[i];//}//delete[]H->TheLists;//delete H;//}////Position Find(ElementType Key, HashTable H)//{//Position P;//List L;////L = H->TheLists[Hash(atoi(&Key[6]), H->TableSize)];//P = L->Next;//while (P != nullptr && P->PhoneNum != Key) {//P = P->Next;//}//return P;//}////void Insert(ElementType Key, HashTable H)//{//Position Pos, NewCell;//List L;//////Pos = Find(Key, H);//L = H->TheLists[Hash(atoi(&Key[6]), H->TableSize)];//Pos = L->Next;//while (Pos != nullptr && Pos->PhoneNum != Key) {//Pos = Pos->Next;//}////if (nullptr == Pos) {//NewCell = new ListNode;////L = H->TheLists[Hash(Key, H->TableSize)];//NewCell->PhoneNum = Key;//NewCell->cnt = 1;//NewCell->Next = L->Next;//L->Next = NewCell;//} else {//++(Pos->cnt);//}//}////Index Hash(int Key, int TableSize)//{//return Key % TableSize;////return atoi(&Key[6]) % TableSize;//}////void FindMax(HashTable H)//{//Position P;// maxP = H->TheLists[0]->Next;//int maxCnt = 0, maxSame;//string MinPhone;////maxSame = 1;//for (int i = 0; i != H->TableSize; ++i) {//P = H->TheLists[i]->Next;//while (P != nullptr) {//if (P->cnt > maxCnt) {////maxP = P;//MinPhone = P->PhoneNum;//maxCnt = P->cnt;//maxSame = 1;//} else if (P->cnt == maxCnt) {//if (P->PhoneNum < MinPhone) {////maxP = P;//MinPhone = P->PhoneNum;//}//++maxSame;//}//P = P->Next;//}//}//cout << MinPhone << " " << maxCnt;//if (1 < maxSame) {//cout << " " << maxSame;//}//cout << endl;//}// improve 3#include <iostream>#include <string>#include <cstdlib> //atoi#include <cstring> //#include <ctime>clock_t start, stop;double duration;using namespace std;typedef int Index;typedef char ElementType[12];typedef struct ListNode *Position;typedef Position List;struct ListNode {ElementType PhoneNum;int cnt;Position Next;};struct HashTbl {List *TheLists;int TableSize;};typedef struct HashTbl *HashTable;int NextPrime(int x);HashTable InitializeTable(int TableSize);void DestroyTable(HashTable H);void Insert(ElementType Key, HashTable H);Position Find(ElementType Key, HashTable H);Index Hash(int Key, int TableSize);void FindMax(HashTable H);int main(){HashTable H;int N, maxSame = 1;char send[12], rec[12];//start = clock();cin >> N;H = InitializeTable(2 * N);//stop = clock();//duration = ((double)(stop - start)) / CLK_TCK;//cout << duration << endl;//start = clock();for (int i = 0; i != N; ++i) {cin >> send >> rec;//cout << send << " " << rec << endl;Insert(send, H);Insert(rec, H);}//stop = clock();//duration = ((double)(stop - start)) / CLK_TCK;//cout << duration << endl;//start = clock();FindMax(H);//stop = clock();//duration = ((double)(stop - start)) / CLK_TCK;//cout << duration << endl;DestroyTable(H);}int NextPrime(int x){for (int Next = x;; ++Next) {int i;for (i = 2; i * i <= Next; ++i) {if (Next % i == 0) break;}if (i * i > Next) {return Next;}}}//HashTable : Separate ChainingHashTable InitializeTable(int TableSize){HashTable H;H = new HashTbl;H->TableSize = NextPrime(TableSize);H->TheLists = new List[H->TableSize];for (int i = 0; i != H->TableSize; ++i) {H->TheLists[i] = new ListNode;H->TheLists[i]->Next = nullptr;}return H;}void DestroyTable(HashTable H){for (int i = 0; i != H->TableSize; ++i) {delete H->TheLists[i];}delete[]H->TheLists;delete H;}Position Find(ElementType Key, HashTable H){Position P;List L;L = H->TheLists[Hash(atoi(&Key[6]), H->TableSize)];P = L->Next;while (P != nullptr && P->PhoneNum != Key) {P = P->Next;}return P;}void Insert(ElementType Key, HashTable H){Position Pos, NewCell;List L;//Pos = Find(Key, H);L = H->TheLists[Hash(atoi(Key + 6), H->TableSize)];//Pos = L->Next;while (Pos != nullptr && strcmp(Pos->PhoneNum, Key)){Pos = Pos->Next;}if (nullptr == Pos) {NewCell = new ListNode;//L = H->TheLists[Hash(Key, H->TableSize)];strcpy(NewCell->PhoneNum, Key);NewCell->cnt = 1;NewCell->Next = L->Next;L->Next = NewCell;} else {++(Pos->cnt);}}Index Hash(int Key, int TableSize){return Key % TableSize;//return atoi(&Key[6]) % TableSize;}void FindMax(HashTable H){Position P;// maxP = H->TheLists[0]->Next;int maxCnt = 0, maxSame;string MinPhone;maxSame = 1;for (int i = 0; i != H->TableSize; ++i) {P = H->TheLists[i]->Next;while (P != nullptr) {if (P->cnt > maxCnt) {//maxP = P;MinPhone = P->PhoneNum;maxCnt = P->cnt;maxSame = 1;} else if (P->cnt == maxCnt) {if (P->PhoneNum < MinPhone) {//maxP = P;MinPhone = P->PhoneNum;}++maxSame;}P = P->Next;}}cout << MinPhone << " " << maxCnt;if (1 < maxSame) {cout << " " << maxSame;}cout << endl;}




1 0
原创粉丝点击