看前须知
第二次上机题汇总
题目内容
问题描述
读取一组电话号码簿(由姓名和手机号码组成),将重复出现的项删除(姓名和电话号码都相同的项为重复项,只保留第一次出现的项),并对姓名相同手机号码不同的项进行如下整理:首次出现的项不作处理,第一次重复的姓名后面加英文下划线字符_和数字1,第二次重复的姓名后面加英文下划线字符_和数字2,依次类推。号码簿中姓名相同的项数最多不超过10个。最后对整理后的电话号码簿按照姓名进行从小到大排序,并输出排序后的电话号码簿。
输入形式
先从标准输入读取电话号码个数,然后分行输入姓名和电话号码,姓名由不超过20个英文小写字母组成,电话号码由11位数字字符组成,姓名和电话号码之间以一个空格分隔,输入的姓名和电话号码项不超过100个。
输出形式
按照姓名从小到大的顺序分行输出最终的排序结果,先输出姓名再输出电话号码,以一个空格分隔。
样例
15
liping 13512345678
zhaohong 13838929457
qiansan 13900223399
zhouhao 18578294857
anhai 13573948758
liping 13512345678
zhaohong 13588339922
liping 13833220099
boliang 15033778877
zhaohong 13838922222
tianyang 18987283746
sunnan 13599882764
zhaohong 13099228475
liushifeng 13874763899
caibiao 13923567890
【样例输出】
anhai 13573948758
boliang 15033778877
caibiao 13923567890
liping 13512345678
liping_1 13833220099
liushifeng 13874763899
qiansan 13900223399
sunnan 13599882764
tianyang 18987283746
zhaohong 13838929457
zhaohong_1 13588339922
zhaohong_2 13838922222
zhaohong_3 13099228475
zhouhao 18578294857
样例说明
输入了15个人名和电话号码。其中第一项和第六项完全相同,都是“liping 13512345678”,将第六项删除,第一项保留;
第八项和第一项人名相同,电话不同,则将第八项的人民整理为liping_1;同样,第二项、第七项、第十项、第十三项的人名都相同,将后面三项的人名分别整理为:zhaohong_1、zhaohong_2和zhaohong_3。
最后将整理后的电话簿按照姓名进行从小到大排序,分行输出排序结果。
题解
易错点和难点
这道题的难点就在与结构体的多级排序,对于结构体的多级排序的操作,用qsort是最容易解决的,关键就在于怎么编写qsort中的cmp(const voidp1,const voidp2)函数,这里其实就是套路,首先先进行结构体指针的转换,之后在按照要求进行return 中的内容比较,如果是多级排序,则是是用条件判断语句 if 进行多级return操作就可以了。
参考代码
#include<stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<ctype.h>
struct student{ //存储学生信息的结构体
char name[105]; //姓名
char num[105]; //电话号码
};
typedef struct student Stu;
int cmp(const void*p1,const void*p2);
int main()
{
int n,i,j;
int cnt=1,cnt2=0;
Stu infor[105];
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%s %s",&infor[i].name,&infor[i].num);//录入信息
}
//qsort(infor,n,sizeof(Stu),cmp);
for(i=0;i<n;i++)
{
cnt=1;
for(j=i+1;j<n;j++)
{
if(strcmp(infor[j].name,infor[i].name)==0 && strcmp(infor[j].num,infor[i].num)==0)//完全相同
{
memset(infor[j].name,0,sizeof(infor[j].name));//清空
memset(infor[j].num,0,sizeof(infor[j].num));//清空
cnt2++;
}
if(strcmp(infor[j].name,infor[i].name)==0 && strcmp(infor[j].num,infor[i].num)!=0)//仅姓名相同
{
int len=strlen(infor[j].name);//进行重复处理
infor[j].name[len]='_';
char figure=cnt+'0';
infor[j].name[len+1]=figure;
cnt++;
}
}
}
qsort(infor,n,sizeof(Stu),cmp);//结构体排序******注意sizeof里的内容
for(i=0;i<n;i++)
{
printf("%s %s\n",infor[i].name,infor[i].num);
printf("\n");
}
return 0;
}
int cmp(const void*p1,const void*p2)//结构体排序——比较字典序
{
struct student *a=(struct student*)p1;
struct student *b=(struct student*)p2;
return strcmp(a->name,b->name);//比较字典序
}
补充测试的数据
如果结构体排序和姓名重复但号码不重复时对姓名的操作这两者的操作都成功,那么这道题没有上面需要补充的测试数据。