PTA:电话聊天狂人(链表数组法)

PTA:电话聊天狂人

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

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

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

输入样例:
4
13005711862 13588625832
13505711862 13088625832
13588625832 18087925832
15005713862 13588625832

输出样例:
13588625832 3

解法1(非散列):对每个输入的号码直接排序即可,然后依次进行相应统计。这个方法当然就好在代码写起来很快,很简洁。但是失去了一次练习散列和指针的机会。

解法2:运用散列,相同的元素对应的关键码一定相同,大大加快了查找相同元素的时间。那么对于这里,无法确定一个关键码最多可能对应多少Key的情况,可以选择用链表数组来进行操作。
重要步骤:确定散列函数。这里就用较为简单的取余法,进行散列。那么此时,自然是要求出一个合适的素数M。那么首先要确定M肯定大于2N,因为有可能所有电话号码都不一样。那求这个M可以有很多方法,可以往2N后不断找奇数,然后碰到一个素数就停止。我的方法比较暴力,直接把所有可能的M值都存在一个素数数组里面,然后输入N以后就直接遍历整个数组找到正确的M。
重要定义

struct k
{
    char number[12];
    int cishu;
    struct k *next=NULL;
};
k *x[300000];

x即链表数组,头元素就是第一个元素,手动增加一个哨兵元素也可以,但是这里没有哨兵元素也不会很麻烦。这里还要注意一定要定义计数器。
代码中的重要函数:
1.myfind(char [ ]):其目标就是找到合适的位置pos,若该链上有相同元素则让该Key的计数器+1即可,并且直接返回-1,代表不用再进行其他操作。相反,倘若没有找到,则返回其位置pos。
2.myinsert(char [ ]):那么很显然这是个插入元素的函数,在输入时就可以直接调用插入。用myinsert时先调用myfind,返回-1就自然不用再进行操作,直接出去。倘若返回的pos那么代表要进行操作,然后这里需要特判是否要插入的链表还没有一个Key(增加了一个空的头节点的话,也就是哨兵元素的话就不用特判),然后视具体情况进行相应简单插入操作就可以了。

代码:

#include<bits/stdc++.h>
using namespace std;
bool visited[300000];
int prime[200000];
int n,M;
int EE(int n)
{
    for(int i=0;i<=n;++i)visited[i]=false;
    for(int i=2;i*i<=n;++i)
        if(!visited[i])
        for(int j=i*i;j<=n;j+=i)
        visited[j]=true;
    int k=0;
    for(int i=2;i<=n;++i)
        if(!visited[i])
        prime[k++]=i;
    return k;
}
struct k
{
    char number[12];
    int cishu;
    struct k *next=NULL;
};
k *x[300000];
int maxci=-1,maxren=0;
char ans[12];
int myfind(char y[])
{
    int pos=atoi(y+5)%M;
    k *p=x[pos];
    while(p)
    {
        if(strcmp(p->number,y)==0){
            p->cishu++;
            return -1;}
        p=p->next;
    }
    return pos;
}
void myinsert(char y[])
{
    int pos=myfind(y);
    if(pos!=-1){
    if(x[pos]==NULL)
    {
        x[pos]=(k*)malloc(sizeof(k));
        x[pos]->cishu=1;
        strcpy(x[pos]->number,y);
        x[pos]->next=NULL;
    }
    else
    {
        k *p=x[pos]->next,*t=(k*)malloc(sizeof(k));
        t->cishu=1;
        strcpy(t->number,y);
        t->next=p;
        x[pos]->next=t;
    }
    }
}
void scanlist()
{
    for(int i=0;i<M;++i)
    {
        k *p=x[i];
        while(p)
        {
            if(p->cishu>maxci)
            {
                maxci=p->cishu;
                maxren=1;
                strcpy(ans,p->number);
                p=p->next;
                continue;
            }
            if(p->cishu==maxci)
            {
                maxren++;
                if(strcmp(p->number,ans)<0)
                strcpy(ans,p->number);
                p=p->next;
                continue;
            }
            p=p->next;
        }
    }
}
int main()
{
    EE(200009);
    char x1[12],x2[12];
    cin>>n;
    for(int i=0;;++i)
    {
        if(prime[i]>2*n)
        {
            M=prime[i];
            break;
        }
    }
    for(int i=0;i<n;++i)
    {
        cin>>x1;
        myinsert(x1);
        cin>>x2;
        myinsert(x2);
    }
    scanlist();
    cout<<ans<<' '<<maxci;
    if(maxren!=1)
        cout<<' '<<maxren;
} 
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值