2016 上半年软件评测师考试真题及答案-下午卷
试题一
阅读以下说明和流程图,填补流程图和问题中的空缺(1)~(5),将解答填入答题纸的对
应栏内。
【说明】
设整型数组 A[1:N]每个元素的值都是 1 到 N 之间的正整数。一般来说,其中会有一些
元素的值是重复的,也有些数未出现在数组中。下面流程图的功能是查缺查重,即找出 A[1:
N]中所有缺的或重复的整数,并计算其出现的次数(出现次数为 0 时表示缺)。流程图中采
用的算法思想是将数组 A 的下标与值看作是整数集[1:N]加上的一个映射,并用数组 C[1:
N]记录各整数出现的次数,需输出所有缺少的或重复的数及其出现的次数。
【流程图】
【问题】
如果数组 A[1:5]的元素分别为{3,2,5,5,1},则算法流程结束后输出结果为:
(5) 输出格式为:缺少或重复的元素,次数(0 表示缺少)
参考答案:
(1)A[i]
(2)C[k]+1
(3)0
(4)k
和 C[k]
(5)4,{1,1,1,0,2}
试题分析:
(1)A[i]
//A[i]赋给 K,
(2)C[k]+1//C[k]值加 1,i 循环中,将 A{i}中存在的值在 C[k]中相应位数上加 1。以
A[1:5]={3,2,5,5,1}为例,当 i=1 时,k=A[1]=3,则 C[3]+1,即 C[1:5]变成{0,0,1,
0,0}。
(3)0
//判断 C[k]值是否为 0,为零这说明 k 未缺少值
(4)k
和 C[k]
//k 位重复数,C[k]为重复次数
(5)在范例中,4 没有出现,1、2、3 分别出现了 1 次,5 出现了两次。
试题二
阅读以下说明和 C 代码,填补代码中的空缺,将解答填入答题纸的对应栏内。
【说明 1】
递归函数 is_elem(char ch, char *set)的功能是判断 ch 中的字符是否在 set 表示的
字符集合中,若是,则返回 1,否则返回 0。
【C 代码 1】
int is_elem (char ch ,char*set)
{
}
If(*set==‘\0’)
return 0;
else
If((1))
return 1;
else
return is_elem((2))
【说明 2】
函数 char*combine(char* setA,char *setB)的功能是将字符集合 A(元素互异,由 setA
表示)和字符集合 B(元素互异,由 setB 表示)合并,并返回合并后的字符集合。
【C 代码 2】
char*combine(char *setA, char*setB)
{
int i,lenA, lenB, lenC;
lenA=strlen(setA);
lenB=strlen(setB);
char*setC=(char*)malloc(lenA+lenB+1);
if(!setC)
return NULL;
strncpy(setC,setA,lenA);
//将 setA 的前 lenA 个字符复制后存入 setC
lenC = (3);
for(i=0;i<lenB;i++)
if((4))
//调用 is_elem 判断字符是否在 setA 中
setC[lenC++]=setB[i];
(5) =‘/0’;
//设置合并后字符集的结尾标识
return setC;
}
参考答案:
(1)set[0]==ch
(2)ch,*set-1
(3)lenA
(4)is_elem(setB[i],*setA)==0
(5)setC[lenC+1]
试题分析:
If(set[0]==ch)//取出 set 第一个元素与 ch 字符比较是否相等
return
is_elem(ch,*set-1)
// 从 set 第二个元素开始重新递归代入函数执行
strncpy(setC,setA,lenA); //将 setA 的前 lenA 个字符复制后存入 setC
lenC=lenA;
for(i=0;i<lenB;i++)
ifis_elem(setB[i],*setA)==0)
//调用 is_elem 判断字符是否在 setA 中
setC[lenC++]=setB[i];
setC[lenC+1]=‘/0’;
//设置合并后字符集的结尾标识
returnsetC;
试题三
阅读以下说明和 C 代码,填补代码中的空缺,将解答填入答题纸的对应栏内。
【说明】
某文本文件中保存了若干个日期数据,格式如下(年/月/日):
2005/12/1
2013/2/29
1997/10/11
1980/5/15
....
但是其中有些日期是非法的,例如 2013/2/29 是非法日期,闰年(即能被 400 整除或者
能被 4 整除而不能被 100 整除的年份)的 2 月份有 29 天,2013 年不是闰年。现要求将其中
自 1985/1/1 开始、至 2010/12/31 结束的合法日期挑选出来并输出。
下面的 C 代码用于完成上述要求。
【C 代码】
#include
typedef struct{
int year,
month, day;/* 年,月,日*/
}DATE;
int
isLeap
Year(int
y)
/*判断 y 表示的年份是否为闰年,是则返回 1,否则返
回 0*/
{
}
return((y%4==0 && y%100!=0)Il(y%400==0));
int
isLegal(DATE
date)
/*判断 date 表示的日期是否合法,是则返回 1,否则返
回 0*/
{
int
y=date.year,m=date.month,d=date.day;
if(y<1985
II
y>2010
II
m<1
II
m>12
II
d31)
return
if((m==4 ll
m==6
ll
m==9
II
m==11)&&(1)
)
return
0;
If(m==2){
if(isLeap
Year(y) &&
(2))
return
1;
else
if(d28)
return
0;
}
return
1;
0;
}
Int
Lteq(DATE
d1,DATE d2)
/*比较日期 d1 和 d2,若 d1 在 d2 之前或相同则返回 1,否则返回 0*/
{
}
Long t1,t2;
t1=d1.year*10000+d1.month*100+d1.day;
t2=d2.year*10000+d2.month*100+d2.day;
if((3))
return
1;
else
return
0;
int
main()
{
DATE date,start={1985,1,1},end={2010,12,30};
FILE*fp;
fp=fopen(“d.txt”,”r”);
If((4))
return-1;
while(!feof(fp)){
if(fscanf(fp,”%d%d%d”,date.year,date.month,date.day)!=3)
break;
if((5)) /*判断是否为非法日期*/
continue;
if((6)) /*调用 Lteq 判断是否在起至日期之间*/
printf(“%d%d%d\n”,date.year,date.month,date.day);
}
fclose(fp);
Return
0;
}
参考答案:
(1)d>30 / d==31 或其等价表示
(2)d<29 或其等价表示
(3)t1<=t2/t1-t2<=0 或其等价表示
(4)fp==null/!fp 或其等价表示
(5)isLegal(date) 或其等价表示
(6)Lteq(start,date)==1Lteq(date,end)==1 或其等价表示
试题分析:
(1)(2)理解:
if((m==4 ll m==6 llm==9 II m==11)&&
d>30 /d==31)
return 0;
//如果月份是
4,6,9,11 并且天数等于 31 则返回不合法,这几个月最多为 30 天,不可能等于 31。
If(m==2){
if(isLeap Year(y)&&
d<29
)
return 1;
else
if (d>28) return 0;//当年份为闰年的时候,那么二月份的天数需小于或等于
28。合法则返回 1。
(3)if(
t1<=t2/t1-t2<=0
)
return 1;
//d1 在 d2 之前,那么表明日
期经换算成 t1、t2 后,t1<=t2。
fp==null/!fp
(4)If(
(5)(6)理解:
)//先要判断文件是否为空;
if(isLegal(date))
/*判断是否为非法日期 */
continue;
if(Lteq(start,date)==1&&Lteq(date,end)==1 ) /*调用 Lteq 判断是否在起至日期
之间,Lteq(t1,t2)的含义是比较日期 d1 和 d2,若 d1 在 d2 之前或相同则返回 1,否则
返回 0。*/