给定大量手机用户通话记录,找出其中通话次数最多的聊天狂人。
输入格式:
输入首先给出正整数N(≤10^5),为通话记录条数。随后N行,每行给出一条通话记录。简单起见,这里只列出拨出方和接收方的11位数字构成的手机号码,其中以空格分隔。
输出格式:
在一行中给出聊天狂人的手机号码及其通话次数,其间以空格分隔。如果这样的人不唯一,则输出狂人中最小的号码及其通话次数,并且附加给出并列狂人的人数。
输入样例:
4
13005711862 13588625832
13505711862 13088625832
13588625832 18087925832
15005713862 13588625832
输出样例:
13588625832 3
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 #include <math.h> 6 using namespace std; 7 8 #define MAXTABLESIZE 1000000 /* 允许开辟的最大散列表长度 */ 9 #define KEYLENGTH 11 /* 关键词字符串的最大长度 */ 10 #define MAXD 5 /*参与散列映射计算的字符数*/ 11 typedef char ElementType[KEYLENGTH+1]; /* 关键词类型用字符串 */ 12 typedef int Index; /* 散列地址类型 */ 13 14 /******** 以下是单链表的定义 ********/ 15 typedef struct LNode *PtrToLNode; 16 struct LNode { 17 ElementType Data; 18 PtrToLNode Next; 19 int Count; 20 }; 21 typedef PtrToLNode Position; 22 typedef PtrToLNode List; 23 /******** 以上是单链表的定义 ********/ 24 25 typedef struct TblNode *HashTable; /* 散列表类型 */ 26 struct TblNode { /* 散列表结点定义 */ 27 int TableSize; /* 表的最大长度 */ 28 List Heads; /* 指向链表头结点的数组 */ 29 }; 30 31 int NextPrime( int N ) 32 { /* 返回大于N且不超过MAXTABLESIZE的最小素数 */ 33 int i, p = (N%2)? N+2 : N+1; /*从大于N的下一个奇数开始 */ 34 35 while( p <= MAXTABLESIZE ) { 36 for( i=(int)sqrt(p); i>2; i-- ) 37 if ( !(p%i) ) break; /* p不是素数 */ 38 if ( i==2 ) break; /* for正常结束,说明p是素数 */ 39 else p += 2; /* 否则试探下一个奇数 */ 40 } 41 return p; 42 } 43 44 HashTable CreateTable( int TableSize ) 45 { 46 HashTable H; 47 int i; 48 49 H = (HashTable)malloc(sizeof(struct TblNode)); 50 H->TableSize = NextPrime(TableSize);/* 保证散列表最大长度是素数 */ 51 H->Heads = (List)malloc(H->TableSize*sizeof(struct LNode));/* 以下分配链表头结点数组 */ 52 53 /* 初始化表头结点 */ 54 for( i=0; i<H->TableSize; i++ ) { 55 H->Heads[i].Data[0] = '\0'; 56 H->Heads[i].Next = NULL; 57 H->Heads[i].Count = 0; 58 } 59 60 return H; 61 } 62 63 Index Hash(int Key, int TableSize ) 64 { 65 66 return Key % TableSize; 67 } 68 69 70 Position Find( HashTable H, ElementType Key ) 71 { 72 Position P; 73 Index Pos; 74 75 Pos = Hash(atoi(Key+KEYLENGTH-MAXD), H->TableSize ); /* 初始散列位置 */ 76 P = H->Heads[Pos].Next; /* 从该链表的第1个结点开始 */ 77 /* 当未到表尾,并且Key未找到时 */ 78 while( P && strcmp(P->Data, Key) ) 79 P = P->Next; 80 81 return P; /* 此时P或者指向找到的结点,或者为NULL */ 82 } 83 84 bool Insert( HashTable H, ElementType Key ) 85 { 86 Position P, NewCell; 87 Index Pos; 88 89 P = Find( H, Key ); 90 if ( !P ) { /* 关键词未找到,可以插入 */ 91 NewCell = (Position)malloc(sizeof(struct LNode)); 92 strcpy(NewCell->Data, Key); 93 NewCell->Count = 1; 94 Pos = Hash(atoi(Key+KEYLENGTH-MAXD), H->TableSize ); /* 初始散列位置 */ 95 /* 将NewCell插入为H->Heads[Pos]链表的第1个结点 */ 96 NewCell->Next = H->Heads[Pos].Next; 97 H->Heads[Pos].Next = NewCell; 98 return true; 99 } 100 else { /* 关键词已存在 */ 101 P->Count++; 102 return false; 103 } 104 } 105 106 void DestroyTable( HashTable H ) 107 { 108 int i; 109 Position P, Tmp; 110 111 /* 释放每个链表的结点 */ 112 for( i=0; i<H->TableSize; i++ ) { 113 P = H->Heads[i].Next; 114 while( P ) { 115 Tmp = P->Next; 116 free( P ); 117 P = Tmp; 118 } 119 } 120 free( H->Heads ); /* 释放头结点数组 */ 121 free( H ); /* 释放散列表结点 */ 122 } 123 124 void ScanAndOutput( HashTable H ) 125 { 126 int MaxCnt = 0, PCnt = 0; //MaxCnt最大通话次数 127 ElementType MinPhone; 128 List Ptr; 129 MinPhone[0] = '\0'; 130 131 for(int i = 0; i < H->TableSize; i++) { //扫描链表 132 Ptr = H->Heads[i].Next; 133 while(Ptr) { 134 if (Ptr->Count > MaxCnt) { //更新最大通话次数 135 MaxCnt = Ptr->Count; 136 strcpy(MinPhone, Ptr->Data); 137 PCnt = 1; 138 } 139 else if (Ptr->Count == MaxCnt) { 140 PCnt ++; //狂人计数 141 if ( strcmp(MinPhone, Ptr->Data)>0 ) 142 strcpy(MinPhone, Ptr->Data); /* 更新狂人的最小手机号码*/ 143 } 144 Ptr = Ptr->Next; 145 } 146 } 147 printf("%s %d", MinPhone, MaxCnt); 148 if ( PCnt > 1 ) 149 printf(" %d", PCnt); 150 printf("\n"); 151 } 152 153 int main() 154 { 155 HashTable hash; 156 ElementType Key; 157 int N; 158 scanf("%d",&N); 159 hash = CreateTable(N*2); 160 for(int i = 0; i < N; i++) { 161 scanf("%s",Key); 162 Insert(hash, Key); 163 scanf("%s",Key); 164 Insert(hash, Key); 165 } 166 167 ScanAndOutput(hash); 168 DestroyTable(hash); 169 return 0; 170 }