题目描述
给定大量手机用户通话记录,找出其中通话次数最多的聊天狂人。
输入格式
输入首先给出正整数N(≤105),为通话记录条数。随后N行,每行给出一条通话记录。简单起见,这里只列出拨出方和接收方的11位数字构成的手机号码,其中以空格分隔。
输出格式
在一行中给出聊天狂人的手机号码及其通话次数,其间以空格分隔。如果这样的人不唯一,则输出狂人中最小的号码及其通话次数,并且附加给出并列狂人的人数。
输入样例
4
13005711862 13588625832
13505711862 13088625832
13588625832 18087925832
15005713862 13588625832
输出样例
13588625832 3
题解
题意理解:给出所有通话记录,求出出现次数最多的电话号码,如果次数一样多,输出号码数小的那个,并增加输出并列人数。
自顶向下,逐步求精。
使用分离链接法作为哈希表的冲突处理。
抽象数据结构定义:
哈希表结构体 —— 包含哈希表表长和表头指针数组两个域。
分离链接结构体 —— 包含存储元素(这里是号码字符串)、计数器、下一个结点指针三个域。
程序框架:
- 1️⃣ 建立哈希表
- 2️⃣ 读入各个号码,存入哈希表
- 3️⃣ 在哈希表中查找记录并输出结果
1️⃣ 建立哈希表
- 传入参数是哈希表中元素个数
- 需要找到比元素个数大的下一个素数作为表长
- 找下一个素数首先找到元素个数后一个奇数
- 遍历以后的每一个奇数(有最大范围)直到找到质数
- 找质数是从自身的平方开始,逐个去除自身,发现能被除尽就不是质数,一直除到 2 都没有退出说明是质数,除自己和 1 外没有因子
- 确定表长后对表头数组的每个结点进行初始化
- 字符串初始化为空
- 计数器初始化为零,虽然没有意义
- 下一个结点指针初始化为空
2️⃣ 读入号码插入哈希表
- 循环读入字符串,插入哈希表
- 插入函数传入的参数是读入的字符串和哈希表
- 首先查找待插入键值是否在哈希表中已存在
- 如果元素还未存在,执行插入操作
- 要找到表头数组的索引,使用哈希函数求出下标 Pos ,哈希函数传入字符串的后五位对表长取模即可
- 然后在对应的表头执行链表的插入操作
- 如果元素已存在,则无需插入,只需要把计数器加一
- 最后记得写一个销毁哈希表的函数,良好的编程习惯,使用指针记得清除空间
3️⃣ 解决函数
- 首先需要声明使用的计数变量
- MinPhone 存如果有相同次数的狂人存那个号码数最小的,初始化为空字符串
- MaxCnt 存最狂人的通话次数,初始化为 0
- PCnt 存并列最狂人数,初始化为 0
- 遍历哈希表的表头数组,再每次遍历其下的链表
- 如果找到一个元素的 Cnt 比目前的 MaxCnt 大
- 更新 MaxCnt 并且一定要注意的是 PCnt 直接更新成 1 而不是加一,因为每第一次找到新的狂人这时的 PCnt 又是 1 了
- 把该元素的号码复制到 MinPhone
- 如果找到一个元素的 Cnt 与 MaxCnt 相等,说明有并列狂人
- 如果该狂人的 Phonenum 号码数字比 MinPhone 小
- 更新 MinPone ,要保证输出的是号码数最小的狂人
- 如果找到一个元素的 Cnt 比目前的 MaxCnt 大
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>
typedef struct LNode *PtrToLNode;
struct LNode {
char Phonenum[12];
int Cnt;
PtrToLNode Next;
};
typedef struct TblNode *HashTable;
struct TblNode {
int TableSize;
PtrToLNode Heads;
};
int NextPrime(int N)
{
int i, p;
p = (N % 2) ? N + 2 : N + 1;
while (p <= 1000000) {
for (i = (int)sqrt(p); i > 2; i--)
if (!(p % i)) break;
if (i == 2) break;
else p += 2;
}
return p;
}
HashTable CreateTable(int TableSize)
{
HashTable H;
int i;
H = (HashTable)malloc(sizeof(struct TblNode));
H->TableSize = NextPrime(TableSize);
H->Heads = (PtrToLNode)malloc(sizeof(struct LNode) * H->TableSize);
for(i = 0; i < H->TableSize; i++) {
H->Heads[i].Phonenum[0] = '\0';
H->Heads[i].Cnt = 0;
H->Heads[i].Next = NULL;
}
return H;
}
int Hash(int key, int p)
{
return key % p;
}
PtrToLNode Find(HashTable H, char key[])
{
PtrToLNode P;
int Pos;
Pos = Hash(atoi(key + 7), H->TableSize);
P = H->Heads[Pos].Next;
while (P && strcmp(P->Phonenum, key))
P = P->Next;
return P;
}
bool Insert(HashTable H, char key[])
{
PtrToLNode P, NewCell;
int Pos;
P = Find(H, key);
if (!P) {
NewCell = (PtrToLNode)malloc(sizeof(struct LNode));
strcpy(NewCell->Phonenum, key);
NewCell->Cnt = 1;
Pos = Hash(atoi(key + 7), H->TableSize);
NewCell->Next = H->Heads[Pos].Next;
H->Heads[Pos].Next = NewCell;
return true;
} else {
P->Cnt++;
return false;
}
}
void FreeTable(HashTable H)
{
int i;
PtrToLNode p, tmp;
for (i = 0; i < H->TableSize; i++) {
p = H->Heads[i].Next;
while (p) {
tmp = p;
p = p->Next;
free(tmp);
}
}
free(H);
}
void Solve(HashTable H)
{
int i, MaxCnt, PCnt;
char MinPhone[12];
PtrToLNode Ptr;
MaxCnt = PCnt = 0;
MinPhone[0] = '\0';
for (i = 0; i < H->TableSize; i++) {
Ptr = H->Heads[i].Next;
while (Ptr) {
if (Ptr->Cnt > MaxCnt) {
MaxCnt = Ptr->Cnt;
strcpy(MinPhone, Ptr->Phonenum);
PCnt = 1;
} else if (Ptr->Cnt == MaxCnt) {
PCnt++;
if (strcmp(MinPhone, Ptr->Phonenum) > 0)
strcpy(MinPhone, Ptr->Phonenum);
}
Ptr = Ptr->Next;
}
}
printf("%s %d", MinPhone, MaxCnt);
if (PCnt > 1) printf(" %d", PCnt);
}
int main()
{
int i, N;
char key[12];
HashTable H;
scanf("%d", &N); getchar();
H = CreateTable(N * 2);
for (i = 0; i < N; i++) {
scanf("%s", key); getchar();
Insert(H, key);
scanf("%s", key); getchar();
Insert(H, key);
}
Solve(H);
FreeTable(H);
return 0;
}