11-散列1 电话聊天狂人

155 阅读5分钟

题目描述

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

输入格式

输入首先给出正整数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 ,要保证输出的是号码数最小的狂人
#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;
}