7-14 电话聊天狂人(25 分)(Hash表基本操作)

 

7-14 电话聊天狂人(25 分)

 

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

输入格式:

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

输出格式:

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

输入样例:

4
13005711862 13588625832
13505711862 13088625832
13588625832 18087925832
15005713862 13588625832

输出样例:

13588625832 3

 

我觉得这道题用Hash表做还是有点烦的,特意跑去看了浙大慕课的视频

 

  1 #include <stdio.h>  
  2 #include <stdlib.h>  
  3 #include <string.h>  
  4 #include <math.h>  
  5 #define KEYLENGTH 12        //关键词字符串最大长度  
  6 #define MAXTABLESIZE 1000000    //允许开辟的最大散列表长度  
  7 #define MAXD 5      //参与散列映射计算的字符个数  
  8 typedef char ElementType[KEYLENGTH ];  
  9 typedef int Index; //散列地址类型  
 10   
 11 //单链表定义  
 12 typedef struct LNode *PtrToLNode;  
 13 struct LNode {  
 14     ElementType Data;  
 15     PtrToLNode Next;  
 16     int Count;  
 17 };  
 18 typedef PtrToLNode Position;  
 19 typedef PtrToLNode List;  
 20   
 21 //散列表结点定义  
 22 typedef struct TblNode *HashTable;  //散列表类型  
 23 struct TblNode {  
 24     int TableSize; //表的最大长度  
 25     List Heads;    //指向链表头结点的数组  
 26 };  
 27   
 28 int NextPrime( int N ) {  
 29     //返回大于N且不超过MAXTABLESIZE的最小素数  
 30     int i, p = ( N % 2 ) ? N + 2 : N + 1;   //从大于N的下一个奇数开始  
 31     while ( p <= MAXTABLESIZE ) {  
 32         double q = p;  
 33         for ( i = (int)sqrt(q); i > 2; i-- )  
 34             if ( !(p % i) ) break; //p不是素数  
 35         if ( i == 2 ) break; // for正常结束,说明p是素数  
 36         else p += 2; //否则试探下一个奇数  
 37     }  
 38     return p;  
 39 }  
 40   
 41 HashTable CreateTable ( int TableSize ) {  
 42     HashTable H;  
 43     int i;  
 44     H = (HashTable)malloc(sizeof(struct TblNode));  
 45     H->TableSize = NextPrime(TableSize); //保证散列表最大长度是素数  
 46     //以下分配链表头结点数组  
 47     H->Heads = (List)malloc(H->TableSize * sizeof(struct LNode)); //分配表头结点数组空间  
 48     for ( i = 0; i < H->TableSize; i++ ) { //初始化表头结点  
 49         H->Heads[i].Data[0] = '\0';  
 50         H->Heads[i].Next = NULL;    //链表为NULL  
 51         H->Heads[i].Count = 0;  //对应号码的个数为0  
 52     }  
 53     return H;   //最后将表头结点数组的首地址返回  
 54 }  
 55   
 56 //hash函数  
 57 Index Hash ( const char *Key, int TableSize ) {  
 58     unsigned int h = 0; //散列函数值,初始化为0  
 59     while ( *Key != '\0' ) //位移映射  
 60         h = ( h << 5 ) + *Key++;    //左移五位
 61     return h % TableSize;  
 62 }  
 63   
 64 Position Find ( HashTable H, ElementType Key ) {  
 65     Position P;  
 66     Index Pos;  
 67     Pos = Hash( Key + KEYLENGTH - MAXD, H->TableSize ); //初始散列位置(利用hash函数快速定位)  
 68     P = H->Heads[Pos].Next;     //从该链表的第1个结点开始  
 69     while ( P && strcmp( P->Data, Key ) )   //寻找是否有Key,退出的条件:P为NULL, 或者是找到了  
 70         P = P->Next;  
 71   
 72     return P;   //此时P或者指向找到的结点,或者为NULL  
 73 }  
 74   
 75 int Insert ( HashTable H, ElementType Key ) {  
 76     Position P, NewCell;  
 77     Index Pos;  
 78     P = Find( H, Key ); //先定位:找到or找不到  
 79     if ( !P ) { //关键词未找到,可以插入(声明临时节点存储待插入的数据,然后利用hash函数找到对应的位置,之后是链表的头插法)  
 80         NewCell = (Position)malloc(sizeof(struct LNode));  
 81         strcpy(NewCell->Data, Key);  
 82         NewCell->Count = 1; //个数+1  
 83         Pos = Hash( Key + KEYLENGTH - MAXD, H->TableSize ); //初始散列位置  
 84         //将NewCell插入为H->Heads[Pos]链表的第一个结点(头插法)  
 85         NewCell->Next = H->Heads[Pos].Next;  
 86         H->Heads[Pos].Next = NewCell;  
 87   
 88         return 1;  
 89     }  
 90     else { //关键词已存在  
 91         P->Count++;  
 92         return 0;  
 93     }  
 94 }  
 95   
 96 void DestroyTable( HashTable H ) {  //释放空间  
 97     int i;  
 98     Position P, Tmp;  
 99     //释放每个链表的结点  
100     for( i = 0; i < H->TableSize; i++ ) {  
101         P = H->Heads[i].Next;  
102         while ( P ) {   //依次释放链表每一个元素的空间  
103             Tmp = P->Next;  
104             free( P );  
105             P = Tmp;  
106         }  
107     }  
108     free( H->Heads ); //释放头结点数组  
109     free( H );        //释放散列表头结点  
110 }  
111   
112 void ScanAndOutput ( HashTable H ) {  
113     int i, MaxCnt = 0, PCnt = 0;  
114     ElementType MinPhone;  
115     List Ptr;  
116     MinPhone[0] = '\0';  
117     for ( i = 0; i < H->TableSize; i++ ) { //扫描链表  
118         Ptr = H->Heads[i].Next; //从该链表的第1个结点开始  
119         while ( Ptr ) {  
120             //要找最大的通话次数  
121             if ( Ptr->Count > MaxCnt ) { //更新最大通话次数  
122                 MaxCnt = Ptr->Count;  
123                 strcpy( MinPhone, Ptr->Data );  
124                 PCnt = 1;  
125             }  
126             else if ( Ptr->Count == MaxCnt ) {  
127                 PCnt++; //狂人计数  
128                 if ( strcmp( MinPhone, Ptr->Data ) > 0 )  
129                     strcpy( MinPhone, Ptr->Data ); //更新狂人的最小手机号码  
130             }  
131             Ptr = Ptr->Next;  
132         }  
133     }  
134     printf("%s %d", MinPhone, MaxCnt);  
135     if ( PCnt > 1 )  
136         printf(" %d", PCnt);  
137     printf("\n");  
138 }  
139 int main () {  
140     int N, i;  
141     ElementType Key;  
142     HashTable H;  
143     scanf("%d", &N);  
144     H = CreateTable( N * 2 );   //创建一个散列表  
145     for ( i = 0; i < N; i++ ) {  
146         scanf("%s", Key); Insert( H, Key );  
147         scanf("%s", Key); Insert( H, Key );  
148     }  
149     ScanAndOutput( H );  
150     DestroyTable( H );  
151   
152     return 0;  
153 }

 

 

 

                 

 

                    

posted @ 2018-01-26 16:44  yuxiaoba  阅读(1552)  评论(0编辑  收藏  举报