95005 “请你编程”讲评

Author: 河南 刘卫东 Date: 1995-05-26

        以答卷的情况看主要有三种思路。
        思路一:给每个候奖人一个随机的编号,然后按编号从大到小或从小到大选出前N名作为获奖者。
        思路二:给每个候奖人一个随机的编号,此编号和候奖人姓名组合成新的字符串。然后比较各字符串的大小以确定前N名获奖者。
        思路三:候奖人姓名存放于一个字符串数组中。随机产生N个整数作为数组的下标,根据这些下标就可以索引出全部N名获奖者。
        我们来看一下怎样用C语言实现第三种思路。选定义要用到的几个变量:
        int t,w,i,r;
        char (*name)[9],n[9];
        其中T存贮候奖人数,W存贮获奖人数。name被定义为指针,这个指针指向一个字符数组。这个定义比较难理解些,属于比较复杂的指针说明。这时可按如下原则来理解:以标识符为中心,一对方括号一般表示数组,一对圆括号一般表示函数或强调某一优先顺序。方括号对和圆括号对为同一优先级,且比*号为高。如int *(*lpfn)(),lpfn是一个指针,这个指针指向一个函数,这个函数返回一个指向整数的指针。
        如下程序段实现由用户输入数据:
        printf("请输入候奖人数:");
        scanf("%d",&t);
        printf("请输入获奖人数:");
        scanf("%d",&w);
        name=(char(*)[])malloc(t*9*sizeof(char));
        for(i=0;i<t;i++){
        printf("第%d个姓名为:",i+1);
        scanf("%s",name[i]);
        }
        如下程序段实现随机抽奖:
        randomize();
        for(i=0;y<w;i++){
        r=random(t-i);
        strcpy(n,name[r]);
        strcpy(name[r],name[t-i-1]);
        strcpy(name[t-i-1],n);
        }
        在for循环体中由0到t-i的随机数就可以确定出一名获奖者。三个strcpy调用实现name[r]和name[t-i-1]的对换,以使获奖者恰位于name数组的末尾。
        剩下的工作就是打印获奖者名单,并释放内存:
        for(i=t-w;i<t;i++) puts(name[i]);
        free(name);
        这个程序是由湖北吴云洋同学给出的,它有几个特点:
        首先它避开了比较运算,其次是程序设计思路清晰。可清晰地分为输入程序段、抽奖程序段和输出程序段。整个设计是非常优美的。
        思路一和思路二都用到了比较或排序操作。我们来看一个Basic程序,它是由广州陆文杰给出的:
        INPUT "M,N=",M,N; 输入候奖和获奖人数
        DIM A(M),A$(M) 候奖人姓名存于A$[M]中
        FOR I=1 TO M
        INPUT "Name";A$(I); 输入姓名
        RANDOMIZE TIMER
        A(I)=FIX(RND*1000000); 产生一个随机号码
        A$(I)=STR$(A(I))+"#"+A$(I); 随机号码和姓名
        NEXT I       ;组合成新字符串
        PRINT
        FOR I=1 TO M; 对A$(M)进行排序
        FOR J=I+1 TO M
        IF VAL (A$(I))<VAL(A$(J))THEN
        SWAP A$(I),A$(J)
        NEXT J
        NEXT I
        PRINT
        PRINT "Prize Winner's rotl:";
        for I=1 TO N
        PRINT A$(I)
        NEXT I
        END
        和前面的C程序比较,这个程序效率低些,因为涉及较多比较操作,而且对整个A$数组进行排序也不太必要,因为一般情况下N远小于M。程序中的常数1000000可设定为一个和候奖人数有关的整数,如100*M。另外,这个程序还有一个潜在的问题,即不同的候奖人完全有可能获得一个相同的号码,所以极有可能出现 Val(A$(I))=VAL(A$(J))但只有A$(I)获奖的情况(I<J)。读者可分析一下前面的C程序,看它是如何避免这一情况的。应该说,那里的处理相当巧妙。
        每一期的答卷中都有使用数据库开发语言的,而这一期的题目也特别适合。四川王澎建立了如下的数据库结构:
        字段名   类型  宽度
        姓名     字符  9
        邮编     字符  6
        地址     字符  40
        获奖等级 字符  10
        他写出的抽奖程序可以很容易地加进我们的读者信息管理系统中。
        特别应提到的是广东金菊琴设计的多类型抽奖程序。在那里抽奖类型被归为三类:不分等级的抽奖、分等级但候奖人不重复抽奖、分等级且允许重复抽奖。这样的程序通用性就大大提高了。
        这一期我们采用了吴云洋设计的电脑抽奖程序,抽奖结果是:
        630700 重庆  王澎
        200433 上海  程斌
        134003 吉林  鄢皓
        235038 安徽  丁美怀
        510173 广东  金菊琴
        246001 安徽  何钧军
        226300 通州  郭志坚
        518001 中国  林志鹏
        545005 广西  温永益
        454850 河南  刘卫东