7-15 航空公司VIP客户查询(哈希表的链表实现)

不少航空公司都会提供优惠的会员服务,当某顾客飞行里程累积达到一定数量后,可以使用里程积分直接兑换奖励机票或奖励升舱等服务。现给定某航空公司全体会员的飞行记录,要求实现根据身份证号码快速查询会员里程积分的功能。

输入格式:

输入首先给出两个正整数N(≤105)和K(≤500)。其中K是最低里程,即为照顾乘坐短程航班的会员,航空公司还会将航程低于K公里的航班也按K公里累积。随后N行,每行给出一条飞行记录。飞行记录的输入格式为:18位身份证号码(空格)飞行里程。其中身份证号码由17位数字加最后一位校验码组成,校验码的取值范围为0~9和x共11个符号;飞行里程单位为公里,是(0, 15 000]区间内的整数。然后给出一个正整数M(≤105),随后给出M行查询人的身份证号码。

输出格式:

对每个查询人,给出其当前的里程累积值。如果该人不是会员,则输出No Info。每个查询结果占一行。

输入样例:

4 500
330106199010080419 499
110108198403100012 15000
120104195510156021 800
330106199010080419 1
4
120104195510156021
110108198403100012
330106199010080419
33010619901008041x

输出样例:

800
15000
1000
No Info

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

这个题首先告诉你,只要你懂了歪门邪道的念头大概率都会超时的哟,什么c++的map什么的,别问,问就是我试过,还是要老老实实的用哈希表来做吧,像这种大数据来说,最好不过了,还是老样子,提供c语言版(其实c++里面也有hash函数的,个人在网上查了一些但是搞不太懂,)

1.c语言版

#include <iostream>
#include <queue>
#include <algorithm>
#include <map>
#include <cstdio>
#define maxm 100005
using namespace std;

//看到网上的题解发现string在map中应用时间特别长,所以考虑将字符串转化为long long来看
/*
int main()
{
    map<string ,int> m;
    int n,l;
    cin>>n>>l;
    for(int i=0;i<n;i++)
    {
        string s;
        int x;
        cin>>s>>x;
        x=max(l,x);//最小值为l
        m[s]+=x;//注意可能有相同的
    }
    int k;
    cin>>k;
    while(k--)
    {
        string ss;
        cin>>ss;
        map<string,int>::iterator it=m.find(ss);//查找
        if(it!=m.end())//找到le
        {
            if(m[ss]<l)
                cout<<l<<endl;
            else
                cout<<m[ss]<<endl;
        }
        else
            cout<<"No Info"<<endl;
    }


    return 0;
}
*/
//哈希函数映射,取余10003
//单独构造一个哈希求键值的函数
//还需要单独创建一个单链表来表示身份证号用来找出相同的项进行合并
struct node{
   char s[20];
   int v;
   struct node *next;
   node(){v=0;next=NULL;}
};//哈希节点的构造
node h[maxm];

int Hash(char s[])//哈希转换函数
{
    int idx = 0,i;
    for( i = 0; i < 17; i++)
    {
        idx = (idx*10 + s[i]-'0')%10003;
    }
    if(s[i]=='x') idx = (idx*10 + 11)%10003;
    else idx = (idx*10 + s[i]-'0')%10003;
    return idx;

}
void add(int idx,char s[],int v)//向哈希表中添加节点并合并相同项
{
    int flag=0;//标记
    node *fp=&h[idx];
    node *sp=h[idx].next;
    while(sp)
    {
        if(!strcmp(sp->s,s))
        {
            sp->v+=v;
            flag=1;
            break;
        }
        fp=sp;
        sp=sp->next;
    }
    if(!flag)
    {
        fp->next=new node();
        strcpy(fp->next->s,s);//注意不能用c++的直接赋值会出错fp->next->s=s;
        fp->next->v=v;
    }
}
void find(char s[])//哈希查找
{
    int idx=Hash(s);
    node *fp=&h[idx];
    node *sp=h[idx].next;
    int flag1=0;
     while (sp)
    {
        if (strcmp(sp->s,s) == 0)
        {
            printf("%d\n", sp->v);
            flag1=1;
            break;
        }
        fp = sp;
        sp = sp->next;
    }
    if (!flag1)
        printf("No Info\n");

}
int main()
{
    int n,l;
    cin>>n>>l;
    char s[20];
    for(int i=0;i<n;i++)
    {
        int x;
        scanf("%s %d",s,&x);
        if(x<l)
            x=l;
        int m=Hash(s);
        add(m,s,x);
    }
    int k;
    scanf("%d",&k);
    for(int i=0;i<k;i++)
    {
        scanf("%s",s);
        find(s);
    }
    return 0;
}

其中具体的代码意思我再代码段中做了些注释,应该比较好理解,就不多做解释了,重点就在与不用map的话要将带字符串的记录保存下来,可以将字符串变为数字并且缩小来实现,还有就是注意哈希表的下标表示的就是字符串由哈希函数转换而来的值,而链表的创建可以保证在下标不连续的情况下得以连续遍历来确定有无相同项需要合并。

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【基本要求】 (1)每条航线所涉及的信息有:终点站名、航班号、飞机号、飞行周日(星期几)、乘员定额、余票量、已订票的客户名单(包括姓名、订票量、舱位等级1,2或3)以及等候替补的客户名单(包括姓名、所需票量); (2)作为示意系统,全部数据可以只放在内存中; (3)系统能实现的操作和功能如下: ①查询航线:根据旅客提出的终点站名输出下列信息:航班号、飞机号、星期几飞行,最近一天航班的日期和余票额; ②承办订票业务:根据客户提出的要求(航班号、订票数额)查询该航班票额情况,若尚有余票,则为客户办理订票手续,输出座位号;若已满员或余票额少于订票额,则需重新询问客户要求。若需要,可登记排队候补; ③承办退票业务:根据客户提供的情况(日期、航班),为客户办理退票手续,然后查询该航班是否有人排队候补,首先询问排在第一的客户,若所退票额能满足他的要求,则为他办理订票手续,否则依次询问其他排队候补的客户。 【测试数据】 由读者自行指定。 【实现提示】 两个客户名单可分别由线性和队列实现。为查找方便,已订票客户的线性应按客户姓名有序,并且,为插入和删除方便,应以链表作存储结构。由于预约人数无法预计,队列也应以链表作存储结构。整个系统需汇总各条航线的情况登录在一张线性上,由于航线基本不变,可采用顺序存储结构,并按航班有序或按终点站名有序。每条航线是这张上的一个记录,包含上述8个域、其中乘员名单域为指向乘员名单链表的头指针,等候替补的客户名单域为分别指向队头和队尾的指针。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值