问题 问答题

【说明】 希赛教育集团公司为发展生产向社会公开招聘M个工种的工作人员,每个工种各有不同的编号(1至M)和计划招聘人数。每位应聘者需申报两个工种,并参加公司组织的考试。公司将按应聘者的成绩从高分至低分的顺序进行排队录取。公司的录取原则是:从高分到低分依次对每位应聘者先按其第一志愿录取;当不能按其第一志愿录取时,便将他的成绩扣去5分后,重新排队,并按其第二志愿考虑录取。 程序为输出各工种实际招聘的应聘人员,每个工种都保留一个录取者的有序队列。录取处理循环直至招聘额满或已对全部应聘者都做了录取处理。 程序中,类型STU包含有应聘者的基本信息:编号、成绩、志愿、排队成绩和录取志愿号。数组rz[]的每个元素对应一个工种,包含有计划招聘人数和已录取的人数。 【程序】 #include<stdio.h> #include<malloc.h> #define M 20 #define PEMARK 5 typedef struct stu{ int no, total, z[2], sortm, zi; struct stu *next; }STU; struct rzmode{ int Imt, count; STU *next; }rz[M]; STU *head=NULL, *over=NULL; int all FILE *fp; char dataf[]="pp07.dat"; print(STU *p){ for(;p!=NULL;p=p->next) printf("%d(%d)\t",p->no,p->total); } insert(STU **p, STU *u){ STU *v, *q; for(q=*p;q!=NULL;v=q, (1) ) if(q->sortm<u->sortm)break; if(q==*p) (2) ; else (3) ; U->next=q; } main(){ int zn, i, no, total, z1, z2; STU *p, *v, *q; fp=fopen(dataf, "r"); if(fp==NULL){ printf("Can’t open file %s.\n",dataf); exit(0); } fscanf(fp, "%d",&zn); for(all=0,i=1;i<=zn;i++){ fscanf(fp,"%d",&rz[i].Imt); rz[i].count=0;rz[i].next=NULL; all+= (4) ; } for(;;){ if((fscanf(fp, "%d%d%d%d",&no,&total,&z1,&z2))!=4) break; p=(STU*)malloc(sizeof(STU)); p->no=no; p->total=p->sortm=total; p->zi=0;p->z[0]=z1;p->z[1]=z2; (5) ; } fclose(fp); for(;all && head !=NULL;){ p=head; head=head->next; if(rz[p->z[p->zi]].count< (6) ){ rz[p->z[p->zi]].count++; insert(&rz[p->z[p->zi]].next,p); all--; continue; } if(p->zi>=1){ p->next=over;over=p; continue; } p->sortm-=DEMARK; (7) ; insed(&head,p); } for(i=1;i<=zn;i++){ printf("%d:\n",i); print(rz[i].next); printf("\n"); } printf("over:\n");print(head); print(over);printf("\n"); }

答案

参考答案:

解析:(1)q=q->next或q=v->next (2)*p=u (3)v->next=u (4)rz[i].1mt (5)insert(&head,p) (6)rz[p->z[p->zi]].1mt (7)p->zi++或p->zi=1

[分析]: 本题考查C语言的基本语法知识。 题目的要求在程序说明中表现得已经很清楚了,下面直接分析程序。 自定义函数insert()是主函数中的常用函数,其功能是向一个降序链表中插入一个元素,使链表仍为降序。 insert(STU **p,STU *u){ STU*v, *q; for(q=*p;q !=NULL; v=q, (1) ) if(q->sortm<u->sortm)break; 上面的循环功能是查找插入点,所以要从q链表的首结点开始逐个与u比较,当q结点的值比u结点的值小时,可以确定u应插入到q之前。因此,(1)空应填q=q->next。 if(q==*p) (2) ; else (3) ; u->next=q; } 这里分两种情况,如果q==*p,表示u结点的插入点为链表首,所以(2)空应填:*p=u;如果q!=*p,表示u结点要插入的位置不是链表首部,又因为v是q的前趋结点(这一点可以从上面的for(..;v==q..)看出),所以(3)空应填v->next=u。 接下来,我们来看主函数main()。 main(){ … for(all=0,i=1;i<=zn;i++){ fscanf(fp,"%d",&rz[i].1mt); rz[i].count=0;rz[i].next=NULL; all+= (4) ; } 由于题目中提到“数组rz[]的每个元素对应一个工种,包含有计划招聘人数和已录取的人数”,结合上面的处理代码,我们可知rz[].1mt是计划招聘人数,rz[].count是已录取人数,all是代表计划招聘总人数,所以(4)空应填rz[i].1mt。 for(;;){ if((fscanf(fp,"%d%d%d%d",&no,&total,&z1,&z2))!=4) break; 这里输入一个应聘者的编号、总成绩、第一志愿、第二志愿。如果输入的数据少于4个,则退出循环。 p=(STU*)malloc(sizeof(STU)); p->no=no; p->total=p->sortm=total; p->zi=0;p->z[0]=z1;p->z[1]=z2; (5) ; } 上面的语句段是为输入的数据建立一个结点,并保存,但如果没有(5)空的处理,当下次执行循环体时,上一次的结点p将被覆盖掉。因此,(5)空的功能应是把结点连成链表。这时我们应想到前面分析过的函数insert(),因为此函数可以把一个结点插入到已知链表中。又因为从下面的语句可以看出head为本程序要处理链表的首指针,所以(5)空应填insert(&head,p)。 fclose(fp); for(;all && head !=NULL;){ 下面这段程序是进行录取工作,all是还要招聘的人数,head是应聘人员的列表。 p=head;head=head->next; 把p结点从head表中删除。 if(rz[p->z[p->zi]].count< (6) ){ 因为题目中有“数组rz[]的每个元素对应一个工种,包含有计划招聘人数和已录取的人数”,所以结合上面的分析可知rz[].count为已招聘人数,rz[].1mt为计划招聘人数。当已招人数还未达到计划招收人数时应继续招聘,所以(6)空应填rz[p->z[p->zi]].1mt。 rz[p->z[p->zi]].count++; insert(&rz[p->z[p->zi]].next,p); 把结点p加入到rz[p->z[p->zi]].next链表中,表示其已被录用。 all--; continue; } 招到一个人后,还要招收的人数就应减1。 p->next=over;over=p; continue; } 从这里可以看出p->zi是应聘次数的标志,其初值为0,如果p->zi>=1,则表示应聘者已经进行完两次应聘,均没有聘上,所以没有资格再进行应聘。用continue语句使循环立即跳到开始处,进行下一名应聘者的录取工作。 p->sortm-=DEMARK; (7) ; 如果程序执行了此语句,则代表p所指示的应聘者第一志愿落选,按题目要求,当不能按其第一志愿录取时,便将他的成绩扣去5分后,重新排队,并按其第二志愿考虑录取。语句p->sortm-=DEMARK用于将他的成绩扣去5分,insert(&head,p)用于重新排队。这样,(7)空看起来似乎没什么用,其实不然。整段程序都没有对p->zi>=1进行调整,而p->zi的值是用于标志此应聘者的应聘次数,当应聘了一次后应加1或直接置1,否则判断条件if(p->zi>=1)永远也不会成立。因此,(7)空应填p->zi++或p->zi=1。

选择题
问答题 简答题