1、中级软件设计师下午试题-101 及答案解析(总分:-4.99,做题时间:90 分钟)一、试题一(总题数:1,分数:-1.00)【说明】某超市的销售业务由一个销售业务管理系统进行管理,该系统每完成一次交易都需要提供顾客发票,其格式如表 1-1 所示。(分数:-1.00)_二、试题二(总题数:1,分数:-1.00)【说明】下面是某租车信息管理系统的介绍:该车库中备有若干车辆,每辆车有车号、车牌、车名、价格等属性。车库不定期地购买并注册新车供用户借用,也可将报废的旧车注销以停止租用。车库可为众多用户提供服务。每个用户在借车之前需注册姓名、地址等内容。每个用户最多可同时借 3 辆车。每辆车借期 7 天
2、:若有一辆车超期,则不可再借其他车。一辆车超期一天罚款 250 元。若一辆车超期3 周不归还,则发布通告。若用户借的车丢失,在罚款处理之前不能借车,每辆报失的车罚款该车目前市价(包括折旧)的 1.2 倍。注册新用户不受限制;而注销用户之前,该用户必须归还所有借的车,或者报失并接受罚款。【状态图 1】【状态图 2】(分数:-0.99)_三、试题三(总题数:1,分数:-1.00)1.阅读下列说明和流程图 2-3,将应填入 (n) 的字句写在答题纸的对应栏内。【说明】下面的流程图描述了对 8 位二进制整数求补的算法。该算法的计算过程如下:从二进制数的低位(最右位)开始,依次向高位逐位查看,直到首次遇
3、到“1”时,停止查看。然后,对该“1”位左面的更高位(如果有的话),逐位求反,所得的结果就是对原二进制数求补的结果。例如:对二进制整数 10101000 求补的结果是 01011000。设 8 位二进制整数中的各位,从低位到高位,依次存放在整型数组 BIT 的 B1T1BIT8中。例如,二进制整数 10101000 存放在数组 BIT 后,就有 BIT1=0,BIT2=0,BIT7 =0,BIT8=1。若流程图中存在空操作,则用 NOP 表示。【流程图】注:流程图中 (1) 处按“循环变量名:循环初值,增量,循环终值”格式描述。(分数:-1.00)_四、试题四(总题数:1,分数:-1.00)2
4、.阅读下列算法说明和算法,将应填入 (n) 的字句写在答题纸的对应栏内。【说明】下列最短路径算法的具体流程如下:首先构造一个只含 n 个顶点的森林,然后依权值从小到大从连通网中选择不使森林中产生回路的边加入到森林中去,直至该森林变成一棵树为止,这棵树便是连通网的最小生成树。该算法的基本思想是:为使生成树上总的权值之和达 到最小,则应使每一条边上的权值尽可能地小,自然应从权值最小的边选起,直至选出 n-1 条互不构成回路的权值最小边为止。(分数:-1.00)_五、试题五(总题数:1,分数:-1.00)3.阅读下列程序说明,将应填入 (n) 处的字句写在答卷纸的对应栏内。【程序说明】对于一个公司的
5、雇员来说,无非有 3 种:普通雇员、管理人员和主管。这些雇员有共同的数据:名字、每小时的工资,也有一些共同的操作:数据成员初始化、读雇员的数据成员及计算雇员的工资。但是,他们也有不同。例如,管理人员除有这些共同的特征外,有可能付固定薪水,主管除有管理人员的共同特征外,还有其他物质奖励等。3 种雇员中,管理人员可以看作普通雇员的一种,而主管又可以看作管理人员的一种。我们很容易想到使用类继承来实现这个问题:普通雇员作为基类,管理人员类从普通雇员类中派生,而主管人员类又从管理人员类中派生。下面的程序 1 完成上述各个类的定义,并建立了 3 个雇员(一个普通雇员、一个管理人员和一个主管)的档案,并打印
6、出各自的工资表。将“程序 1”中的成员函数定义为内联函数,pay 成员函数定义为虚函数,重新完成上述要求。【程序 1】/普通雇员类class Employeepublic:Employee(char *theName, float thePayRate);char *getName0 const;float getPayRate0 const;float pay,(float hours Worked) eonst;protected:ehar *name; /雇员名称float payRate; /薪水等级;Employee:Employee(char *theName, float the
7、PaRate)name = the Name;payRate = the PayRate;char *Employee:getName0 eonstreturn name;float Employee:getPayRate0 constreturn payRate;float Employee:pay(float hoursWorked) constreturn hours Worked * payRate;class Manager: public Employeepublic:/is Salaried 付薪文方式:true 付薪固定工资,false 按小时付薪Manager(char *t
8、he Name, float the Pay Rate, bool is Salaried);bool getSalaried0 const;float pay(float hoursWorked) const;protected:bool salaried;Manager:Manager(ehar *theName,fioat thePayRate,bool isSalaried): Employee(theName, thePayRate)salaried = isSalaried;bool Manager:getSalaried0 eonstreturn salaried;float M
9、anager:pay(float hoursWorked) eonstif (salaried)return payRate;/* else */return Employee:pay(hoursWorked);/主管人员类class Supervisor: public Employeepublic:Supervisor(char *theName, float thePayRate, float theBouns):Employee (theName, thePayRate, (1) .) ,bouns(theBouns) float getBouns0 const return boun
10、s; float pay(float hoursWorked) constreturn (2) ;protected:float houris;#include “iostream.h“void main()Employee e(“Jack“,50.00);Manager m(“Tom“,8000.00,tme);Supervior sCTanya“,8000.00,8000.00);cout“Name:“e.getName0endl;cout “Pay: “e.pay(80)endl; /设每月工作 80 小时cout “Name: “m.getName0endl;cout “Pay: “m
11、.pay(40)endl;cout “Name: “s.getName0endl;cout “Pay: “s.pay(40)endl; /参数 40 在这里不起作用#include “employee.h“class Employeepublic:Employee(string theName, float thePayRate):name(theName),payRate(thePayRate) string getName0 const return name; float getPayRate0 const return payRate; virtual float pay(float
12、hoursWorked) const return (3) ; protected:,string name; /雇员名Boat payRate; /薪水等级;/管理人员类/继承普通雇员类class Manager: public Employeepublic:/构造函数/isSalaried 标识管理人员类的付薪方式/true 按阶段付薪(固定工资)/false 按小时付薪Manager(string theName, float thePayRate, bool isSalaried):Employee(theName,thePayRate),salaried(isSalaried) bo
13、ol getSalaried0 const return salaried; virtual float pay(float (4) ) const;protected:bool salaried;float Manager :pay(float hoursWorked) constif (salaried) /固定付薪方式return payRate;else /按小时付薪return (5) ;/主管人员类class Supervisor: (6) public:/构造函数Supervisor (string theName, float thePayRate, float theBoun
14、s) :Manager(theName, thePayRate, true), bouns(theBouns) /取奖金数额float getBouns0 const return bouns; /计算薪水virtual float pay(float hours Worked) const(7) float bouns;#include “employee.h“#nclude “iostream.h“void main()(8) *ep3;ep0=new Employee(“Jack“ ,“50.00“);ep1=new Manager(“Tom“, “8000.00“,true);ep2=
15、new Supervior(“Tanya“,“8000.00“,“8000.00“);for (int i=0;i3;i+) Cout“Name: “ (9) endl;Cout“Pay: “ (10) endl; /设每月工作 80 小时(分数:-1.00)_中级软件设计师下午试题-101 答案解析(总分:-4.99,做题时间:90 分钟)一、试题一(总题数:1,分数:-1.00)【说明】某超市的销售业务由一个销售业务管理系统进行管理,该系统每完成一次交易都需要提供顾客发票,其格式如表 1-1 所示。(分数:-1.00)_正确答案:(设计一中 Invoice 最高满足第一范式。根据题意可得出
16、以下函数依赖:InoSno,Cno,Idate而关系 Invoice 的主码是 Ino 和 Mno。非主属性 Sno、Cno 和 Idate 并非完全依赖于主码,因此关系Invoice 不满足第二范式,最高满足第一范式。设计二更加合理。因为设计二解决了设计一中由于非主属性不完全依赖于主码而造成的数据冗余等问题。)解析:分析关系数据库设计的方法之一就是设计满足适当范式的模式,通常可以通过判断分解后的模式达到第几范式来评价规范化的程度。11NF(第一范式):若关系模式 R 的每一个分量是不可再分的数据项,则关系模式 R 属于第一范式。22NF(第二范式):若关系模式 R1NF,且每一个非主属性完全
17、依赖于码,则关系模式属于第二范式。当 1NF 消除了非主属性对码的部分函数依赖,则称为 2NF。33NF(第三范式):若关系模式 R(U,F)中若不存在这样的码 X,属性组 Y 及非主属性 Z(Z*Y)使得XY,(YX)YZ 成立,则关系模式属于 3NF。即当 2NF 消除了非主属性对码的传递函数依赖,则称为3NF。4BCNF(巴克斯范式):若关系模式 RlNF,若 XY 且 Y*X 时,X 必含有码,则关系模式属于 BCNF。即当 3NF 消除了主属性对码的部分和传递依赖,则称为 BCNF。54NF(第四范式):关系模式 ReINF,若对于 R 的每个非平凡多值依赖 XY 且 Y*X 时,X
18、 必含有码,则关系模式属于 4NF。4NF 时限制关系模式的属性间不允许有非平凡且非函数依赖的多值依赖。设计一中根据题意可得出以下函数依赖:InoSno,Cno,Idate而关系 Invoice 的主码是 Ino 和 Milo。非主属性 Sno、Cno 和 Idate 并非完全依赖于主码,因此关系Invoice 不满足第二范式,最高满足第一范式。关系 Invoice 的设计的不合理在于该关系中将发票的单值属性(发票号码 Lno,交易日期 Idate,顾客代码 Cno,收银员代码 Sno)和多值属性(商品代码 Mno,单价 unitprice,数量 amount)混合在一个关系中,造成关系 In
19、voice 的冗余异常、修改异常和删除异常。而设计二则将设计一中关系 Invoice 分解,使得发票的单值属性和多值属性分开,避免了异常。因此,设计二明显比设计一要好。_正确答案:(AS(2)SUM(amount)(3)SUM(unitprice*amount)(4)Invoice.Ino=invoice detail. Ino(5)Invoice.Ino,Idate 或 Invoice detail. Ino,Idate)解析:分析本题是要建立 2005 年 1 月期间每张发票的发票号,交易日期,交易商品件数和交易总金额的视图。首先建立视图的格式为 CREATEVIEW视图名AS视图定义,因
20、此(1)空的答案为 AS。本查询是从 Invoice 和 Invoice detail 两个关系中查询,两关系的连接条件是两关系的 Ino 相等,因此(4)空的答案是 Invoice.ino=Invoice detail.Ino。统计每张发票的信息需要按发票将数据分组,也就是按发票号 Ino 分组,但因为查询关系 Invoice 和lnvoice detail 都有属性 Ino。为了避免二义性,所以分组属性是 Invoice.Ino 或者是 Invoice detail. Ino。因为在包含聚合运算的 Select 子句中,只有在 Group By 子句中出现的属性才能在 SELECT 子句中
21、以非聚合形式出现,而 SELECT 子句中有非聚合形式的属性 Idate 出现,所以(5)空的答案是 Invoice.Ino,Idate 或 Invoicedetail.Ino,Idate。需要查询的是每张发票的交易商品件数和交易总金额。交易商品件数是发票商品数量的总和,因此(2)空的答案是 SUM(amount)。交易总金额是每条交易商品明细中每条记录商品金额的总和,每条记录商品金额是 unitprice*amount,因此(3)空的答案是 SUM (unitprice*amount)。_正确答案:(A 和 ASA(2)NOT EXISTS(3) *)解析:分析本题是查询从未售出的商品信息。
22、SQL 语句中有两种格式为表或视图取别名:“表名 AS 别名”或“表名别名”。由题中可以看出Memhandise 的别名是 A,因此填空(1)的答案是 A 或者 ASA。要查询“从未出售”的商品,也就是要查询的商品在交易记录中不存在,因此(2)空的答案是NOTEXISTS。_正确答案:(有必要。Merchandise 中由属性 price 表示的是商品的当前价格,超市中的价格是有可能变动的,而关系 Invoicedetail 中的属性 unitprice 表示的是在开具发票时该商品的单价。)解析:分析Merchandise 中由属性 price 表示的是商品的当前价格,超市中的价格是有可能变动
23、的,而关系 Invoicedetail 中的属性 unitprice 表示的是在开具发票时该商品的单价。如果缺少其中任意一个,将导致商品单价不能进行调整,否则,当商品的单价发生变化时,销售历史中的商品价格就随着发生变化。二、试题二(总题数:1,分数:-1.00)【说明】下面是某租车信息管理系统的介绍:该车库中备有若干车辆,每辆车有车号、车牌、车名、价格等属性。车库不定期地购买并注册新车供用户借用,也可将报废的旧车注销以停止租用。车库可为众多用户提供服务。每个用户在借车之前需注册姓名、地址等内容。每个用户最多可同时借 3 辆车。每辆车借期 7 天:若有一辆车超期,则不可再借其他车。一辆车超期一天
24、罚款 250 元。若一辆车超期3 周不归还,则发布通告。若用户借的车丢失,在罚款处理之前不能借车,每辆报失的车罚款该车目前市价(包括折旧)的 1.2 倍。注册新用户不受限制;而注销用户之前,该用户必须归还所有借的车,或者报失并接受罚款。【状态图 1】【状态图 2】(分数:-0.99)_正确答案:(cancel register(注销旧车的注册)(2)register(车辆注册)(3)return(归还)(4)lost report(遗失报告)解析:分析根据题意可以分析出车辆的状态和事件,例如根据“车库不定期地购买并注册新车供用户借用,也可将报废的旧车注销以停止租用”,可以得出(1)、(2)空分
25、别是注销旧车的注册和车辆注册。(3)空可以从在库状态和在借状态的合理推断,得出从在借状态到在库状态只有一种事件“归还”。从在借状态到终结状态,也只有一种可能性,那就是遗失。_正确答案:(cancel register(注销用户的注册)(6)borrow/n+1(借车/拥有车的数量+1)(7)penalty and n=0(罚款并且拥有车的数量为 0)(8) 3)解析:分析根据题意“注销用户之前,该用户必须归还所有借的车,或者报失并接受罚款”,得出从“No Car到终结状态的事件(5)空是 cancel register(注销用户的注册)。根据从“No Car”到“Has Car”的事件(6)空
26、是 borrow(借车),同时已知用户可以借多辆车,当前拥有车 n 辆,所以需要 n+1。根据“若用户借的车丢失,在罚款处理之前不能借车”可知(7)空是 penalty(罚款),同时状态从“Has Car”到达“No Car”说明 n=0。根据“每个用户最多可同时借 3 辆车”,可以得出(8)空为 3。_正确答案:(活动图(activity diagram)显示动作及其结果。活动图着重描述操作(方法)实现中所完成的工作以及用例实例或对象中的活动。活动图是状态图的一个变种,与状态图的目的有一些小的差别,活动图的主要目的是描述动作(执行的工作和活动)及对象状态改变的结果。当状态中的动作被执行(不像
27、正常的状态图,它不需指定任何事件)时,活动图中的状态(称为动作状态)直接转移到下一个阶段。活动图和状态图的另一个区别是活动图中的动作可以放在泳道中。泳道聚合一组活动,并指定负责人和所属组织。活动图是另一种描述交互的方式,描述采取何种动作,做什么(对象状态改变),何时发生(动作序列),以及在何处发生 (泳道)。活动图可以用作下述目的:1描述个操作执行过程中(操作实现的实例化)所完成的工作(动作)。这是活动图最常见的用途。2描述对象内部的工作。3显示如何执行一组相关的动作,以及这些动作如何影响它们周围的对象。4显示用例的实例是如何执行动作以及如何改变对象状态。说明一次商务活动中的工人(角色)、工作
28、流、组织和对象是如何工作的。)解析:分析所有的系统均有静态结构和动态行为。结构可以用静态模型元素来描述,如类、关系、节点和构件。行为描述结构内的元素如何交互。通常情况下,这些交互是确定的且可以建立模型。抽象系统的动态行为也称为动态建模,UML 支持动态建模。在 UML 中有 4 类图,每一类用于不同的目的:状态、序列、协作和活动。状态图被用来描述类(也可以用于子系统或整个系统)中的行为和内部状态。它着眼于描述随着时间的改变,对象如何改变其状态。状态的改变起决于出现的事件,状态中执行的行为和动作,状态转移等。事件可能是条件成真,接收一个信号或一个操作调用或经过指定时间。序列图主要用来描述在指定情
29、节中一组对象是如何交互的。它着眼于消息序列,也就是说,在对象间如何发送和接收消息。序列图有两个坐标轴:纵坐标轴显示时间,横坐标轴显示有关的对象。序列图中最基本的东西是时间。协作图主要用来描述对象在空间中的交互,即除了动态交互,它也直接描述对象是如何链接在一起的。在协作图中没有时间轴,因而将消息按序编号。三、试题三(总题数:1,分数:-1.00)1.阅读下列说明和流程图 2-3,将应填入 (n) 的字句写在答题纸的对应栏内。【说明】下面的流程图描述了对 8 位二进制整数求补的算法。该算法的计算过程如下:从二进制数的低位(最右位)开始,依次向高位逐位查看,直到首次遇到“1”时,停止查看。然后,对该
30、“1”位左面的更高位(如果有的话),逐位求反,所得的结果就是对原二进制数求补的结果。例如:对二进制整数 10101000 求补的结果是 01011000。设 8 位二进制整数中的各位,从低位到高位,依次存放在整型数组 BIT 的 B1T1BIT8中。例如,二进制整数 10101000 存放在数组 BIT 后,就有 BIT1=0,BIT2=0,BIT7 =0,BIT8=1。若流程图中存在空操作,则用 NOP 表示。【流程图】注:流程图中 (1) 处按“循环变量名:循环初值,增量,循环终值”格式描述。(分数:-1.00)_正确答案:(i:1,1,8(2)1sw(3)0BITi(4)NOP,或空操作
31、(5)1BITi)解析:分析根据题意,从二进制数的低位(最右位)开始,依次向高位逐位查看,直到首次遇到“1”时,停止查看。然后,对该“1”位左面的更高位(如果有的话),逐位求反,所得的结果就是对原二进制数求补的结果。所以(1)空是 8 次循环根据 BITi的值判断相应补数的值, (2)(5)空是分支处理的结果。四、试题四(总题数:1,分数:-1.00)2.阅读下列算法说明和算法,将应填入 (n) 的字句写在答题纸的对应栏内。【说明】下列最短路径算法的具体流程如下:首先构造一个只含 n 个顶点的森林,然后依权值从小到大从连通网中选择不使森林中产生回路的边加入到森林中去,直至该森林变成一棵树为止,
32、这棵树便是连通网的最小生成树。该算法的基本思想是:为使生成树上总的权值之和达 到最小,则应使每一条边上的权值尽可能地小,自然应从权值最小的边选起,直至选出 n-1 条互不构成回路的权值最小边为止。(分数:-1.00)_正确答案:(G.vexnum(2)fix_mfset(F,Locate Vex(e.vex2)(3) !=(4)k+(5)i+)解析:分析本题考查的是克鲁斯卡尔(Kmskal)算法。理解该算法的关键在于:由于生成树上不允许有回路,因此并非每一条居当前权值最小的边都可选。例如,如图 7-1 所示的连通网 G5,在依次选中了(e,f),(b,c),(e,d)和(f,g)的 4 条边之
33、后,权值最小边为(g,d),由于 g 和 d 已经连通,若加上(g,d)这条边将使生成树上产生回路,显然这条边不可取。同理,边(f,d)也不可取,之后则依次取(a,g)和(a,b)两条边加入到生成树。那么在算法中如何判别当前权值最小边的两个顶点之间是否已经连通?从生成树的构造过程可见,初始态为 n 个顶点分属 n 棵树,互不连通,每加入一条边,就将两棵树合并为一棵树,在同一棵树上的两个顶点之间自然相连通。由此判别当前权值最小边是否可取只要判别它的两个顶点是否在同一棵树上即可。五、试题五(总题数:1,分数:-1.00)3.阅读下列程序说明,将应填入 (n) 处的字句写在答卷纸的对应栏内。【程序说
34、明】对于一个公司的雇员来说,无非有 3 种:普通雇员、管理人员和主管。这些雇员有共同的数据:名字、每小时的工资,也有一些共同的操作:数据成员初始化、读雇员的数据成员及计算雇员的工资。但是,他们也有不同。例如,管理人员除有这些共同的特征外,有可能付固定薪水,主管除有管理人员的共同特征外,还有其他物质奖励等。3 种雇员中,管理人员可以看作普通雇员的一种,而主管又可以看作管理人员的一种。我们很容易想到使用类继承来实现这个问题:普通雇员作为基类,管理人员类从普通雇员类中派生,而主管人员类又从管理人员类中派生。下面的程序 1 完成上述各个类的定义,并建立了 3 个雇员(一个普通雇员、一个管理人员和一个主
35、管)的档案,并打印出各自的工资表。将“程序 1”中的成员函数定义为内联函数,pay 成员函数定义为虚函数,重新完成上述要求。【程序 1】/普通雇员类class Employeepublic:Employee(char *theName, float thePayRate);char *getName0 const;float getPayRate0 const;float pay,(float hours Worked) eonst;protected:ehar *name; /雇员名称float payRate; /薪水等级;Employee:Employee(char *theName,
36、float thePaRate)name = the Name;payRate = the PayRate;char *Employee:getName0 eonstreturn name;float Employee:getPayRate0 constreturn payRate;float Employee:pay(float hoursWorked) constreturn hours Worked * payRate;class Manager: public Employeepublic:/is Salaried 付薪文方式:true 付薪固定工资,false 按小时付薪Manage
37、r(char *the Name, float the Pay Rate, bool is Salaried);bool getSalaried0 const;float pay(float hoursWorked) const;protected:bool salaried;Manager:Manager(ehar *theName,fioat thePayRate,bool isSalaried): Employee(theName, thePayRate)salaried = isSalaried;bool Manager:getSalaried0 eonstreturn salarie
38、d;float Manager:pay(float hoursWorked) eonstif (salaried)return payRate;/* else */return Employee:pay(hoursWorked);/主管人员类class Supervisor: public Employeepublic:Supervisor(char *theName, float thePayRate, float theBouns):Employee (theName, thePayRate, (1) .) ,bouns(theBouns) float getBouns0 const re
39、turn bouns; float pay(float hoursWorked) constreturn (2) ;protected:float houris;#include “iostream.h“void main()Employee e(“Jack“,50.00);Manager m(“Tom“,8000.00,tme);Supervior sCTanya“,8000.00,8000.00);cout“Name:“e.getName0endl;cout “Pay: “e.pay(80)endl; /设每月工作 80 小时cout “Name: “m.getName0endl;cout
40、 “Pay: “m.pay(40)endl;cout “Name: “s.getName0endl;cout “Pay: “s.pay(40)endl; /参数 40 在这里不起作用#include “employee.h“class Employeepublic:Employee(string theName, float thePayRate):name(theName),payRate(thePayRate) string getName0 const return name; float getPayRate0 const return payRate; virtual float p
41、ay(float hoursWorked) const return (3) ; protected:,string name; /雇员名Boat payRate; /薪水等级;/管理人员类/继承普通雇员类class Manager: public Employeepublic:/构造函数/isSalaried 标识管理人员类的付薪方式/true 按阶段付薪(固定工资)/false 按小时付薪Manager(string theName, float thePayRate, bool isSalaried):Employee(theName,thePayRate),salaried(isSal
42、aried) bool getSalaried0 const return salaried; virtual float pay(float (4) ) const;protected:bool salaried;float Manager :pay(float hoursWorked) constif (salaried) /固定付薪方式return payRate;else /按小时付薪return (5) ;/主管人员类class Supervisor: (6) public:/构造函数Supervisor (string theName, float thePayRate, floa
43、t theBouns) :Manager(theName, thePayRate, true), bouns(theBouns) /取奖金数额float getBouns0 const return bouns; /计算薪水virtual float pay(float hours Worked) const(7) float bouns;#include “employee.h“#nclude “iostream.h“void main()(8) *ep3;ep0=new Employee(“Jack“ ,“50.00“);ep1=new Manager(“Tom“, “8000.00“,true);ep2=new Supervior(“Tanya“,“8000.00“,“8000.00“);for (int i=0;i3;i+) Cout“Name: “ (9) endl;Cout“Pay: “ (10) endl; /设每月工作