中国科学院软件研究所
一九九六年招收硕士学位研究生入学考试试题答案
试题名称:软件基础
一.1. 表达式 后缀式
①.a+b*c abc*+
②.a≦b+c∧a>d∨a+b≠e abc+≦ad>∧ab+e≠∨
2.①.赋值语句﹤变量﹥:=﹤表达式﹥的逆波兰式表示为:
﹤变量﹥﹤表达式﹥:=
②.条件语句IF﹤表达式﹥THEN﹤语句1﹥ELSE﹤语句2﹥的逆波兰式
表示为:
﹤表达式﹥﹤语句1﹥﹤语句2﹥IF THEN ELSE
或﹤表达式﹥P1 Jez﹤语句1﹥P2 J P1:﹤语句2﹥P2:,其中Jez
是﹤表达式﹥和P1这两个运算对象的二元运算符,表示当﹤表达
式﹥等于0即取假值时转去执行由P1开始的﹤语句2﹥。否则,执
行﹤语句1﹥然后转至P2所指地方;J是无条件转移的一元运算符。
3. ①.四元式序列: ②.三元式序列:
⑴ (- C D T1) ⑴ (- C D)
⑵ (* B T1 T2) ⑵ (* B ⑴)
⑶ (+ A T2 T3) ⑶ (+ A ⑵)
⑷ (- C D T4) ⑷ (- C D)
⑸ (** T4 N T5) ⑸ (** ⑷ N)
⑹ (/ E T5 T6) ⑹ (/ E ⑸)
⑺ (+ T3 T6 T7) ⑺ (+ ⑶ ⑹)
③.间接三元式序列: 间接码表
⑴ (- C D) ⑴
⑵ (* B ⑴) ⑵
⑶ (+ A ⑵) ⑶
⑷ (** ⑴ N) ⑷
⑸ (/ E ⑷) ⑸
⑹ (+ ⑶ ⑸) ⑹
二.解答:满足题意要求的文法G为:
G ={VT,VN,﹤头为非零元整偶数﹥,ρ}
其中,ρ:﹤头为非零元整偶数﹥→ ﹤偶数字1﹥|
﹤非零数字﹥﹤偶数字﹥|
﹤非零数字﹥﹤数﹥﹤偶数字﹥
﹤偶数字﹥ → 0|2|4|6|8
﹤非零数字﹥ → 1|2|3|4|5|6|7|8|9
﹤数﹥ → ﹤数字﹥|﹤数﹥﹤数字﹥
﹤数字﹥ → ﹤非零数字﹥|0
﹤偶数字1﹥ → 2|4|6|8
VN={﹤头为非零元整偶数﹥、﹤偶数字﹥、﹤非零数字﹥、
﹤数﹥、﹤数字﹥}
VT={0,1,2,3,4,5,6,7,8,9}
或者
G =(VT,VN,N,ρ),
其中ρ:N → AD’|D’ (或N→D’|DD’|DAD’)
A → AD”|D (或A→AD”|D”)
D’ → 2|4|6|8
D → 1|3|5|7|9|D’
D” → 0|D;
VN={N,A,D’,D,D”}
VT={0,1,2,3,4,5,6,7,8,9},
N—开始符号。
三.LRU算法的基本思想是:利用局部性原理,根据一个作业在执行过程中过
去的页面访问踪迹来推测未来的行为。它认为过去一段时间不曾被访问过
的页面,在最近的将来可能也不会再被访问。所以该算法的实质是:当需
要置换一页面时,选择在最近一段时间内最久不用的页面予以淘汰。
缺点:实现起来比较困难,因为要对先前的访问历史时时加以记录和更新。
如果这种连续的修改完全由软件来做,系统开销太大;如编硬件执
行,则会增加机器成本。因此,在实际应用中得到推广的是一些简
单而有效的LRU算法。
近似LRU算法流程图:
N
Y
四.1.当缓冲区满时,A进程不可以写,必须等待;
当缓冲区空时,B进程不可以读,必须等待。
2.该算法有错,它对读进程进入临界区未加限制,当缓冲区为空时,也可
以进入临界区读信息;
当存在多个读进程多个写进程时,还需引入一个信号量S0以防止同时
读或同时写。
var S0,S1,S2:semaphore:=1,n,0;
buffer:array [0..n-1] of message;
in,out: 0..n-1:=0,…0;
begin
parbegin
producer: begin
repeat
┇
produce a new message m;
┇
P(S1);
P(S0);
buffer(in):=m;
in:=(in+1) mod n;
V(S0);
V(S2);
until false
end
consumer: begin
repeat
P(S2);
P(S0);
m:=buffer(out);
out:=(out+1) mod n;
V(S0);
V(S1);
consume message m;
until false
end
parend
end
五.解答:当用户创建或联接了一个文件并把它打开后,便可以对它执行读、写
操作。文件系统在进行读写操作时,需调用一系列读写有关的过程,如
⑴ passc过程、cpass过程。前者用于把一字符从缓冲区送到用户区,后
者相反; ⑵ iomove过程用于实现用户区和缓冲区之间的信息传送; ⑶
readi过程用于把信息从磁盘读入内存; ⑷ writei过程用于把信息从
内存写入磁盘。
或:
1.读方式
在UNIX系统中有两种读方式:⑴ 一般读方式。把盘块中的信息读
入缓冲区,有bread过程完成;⑵ 提前读方式。在一个进程顺序地读入
一个文件的各个盘块时,会预见到所要读的下一个盘块,因而在请求读
出指定盘块(作为当前块)的同时,可要求提前将下一个盘块(提前块)
中的信息读入缓冲区。这样,当以后需要该盘块的数据时,因它已在内
存中,这就缩短了读数据时间,从而改善了系统性能。提前读功能由
breada过程完成。
2.写方式
UNIX系统有三种方式:⑴ 一般写方式。真正把缓冲区中的数据写
入磁盘上,且进程须等待写操作完成,由过程bwrite完成;⑵ 异步写
方式。进程无须等待写操作完成便可返回,异步写过程为bawrite;⑶
延迟写方式。该方式并不真正启动磁盘,而只是在缓冲首部设置延迟写
标志,然后便释放该缓冲区,并将该缓冲区链入空闲链表的末尾,以后
当有进程申请到该缓冲区时,才将它写入磁盘。引入延迟写的目的是为
了减少不必要的磁盘I/O,因为只要没有进程申请到此缓冲区,其中的
数据便不会写入磁盘,倘若再有进程需要访问其中的数据时,便可直接
从空闲链表中摘下该缓冲区,而不必从磁盘读入。
六.解答:
设运算变量均为整数的某个简单算术表达式,已加工的为k个四元
式,n1是起始四元式号码,nk是终止四元式号码。由于是加工简单算术表
达式得到的四元式序列,因此这些四元式均为一目或二目算术运算的四元
式。为使存放中间结果的临时单元个数最少,我们设立一个计数器count。
当四元式的第2或第3项出现临时变量(即出现对临时变量的引用时),每
出现一个,计数器就减少1;当四元式的第4项(即存放运算结果的项)
出现临时变量时,计数器就应增加1。
正如前面所述,这些四元式是加工简单算术表达式得到的算术运算四
元式,因此每个四元式必然要把计算结果赋予某个临时变量,因此四元式
的第4项一定是临时变量。
于是对每个算术运算四元式来说,若四元式第2,第3项都是临时变
量时,计数器要减少1;当第2,第3项只有一个是临时变量,计数器不变;
当第2,第3项都不是临时变量时,计数器增加1。
下面给出的算法顺便也给出了临时变量分配的临时单元地址(假定当
前分配的临时变量的起始地址为a)。
Procedure PT(a,n1,nk);
begin
count:=0; p:=0; /* p是临时变量个数*/
for i:=n1 to nk do
begin
if 四元式的第2、3项都是临时变量
then count:=count-1;
if 四元式的第2、3项都不是临时变量
then count:=count+1;
p:=max(p,count);
T[i].ADDR:=a + count –1 /* 保证起始地址为a */
end
end
其中p记录这k个四元式所需临时单元的最大个数;count是计数器。
例如:设有整型的算术表达式为
A*B-C*D+E*F
生成的四元式以及所需最少临时单元如下表所示
四元式 地址 count p
(*,A,B, T1) a 1 1
(*, C, D, T2) a+1 2 2
(-, T1,T2, T3) a 1 2
(*, E, F, T4) a+1 2 2
(+, T3,T4, T5) a 1 2
七.
#define EPSINO 1.0E-10
int pass_plane(points,pno,plane)
float * points; /* points[pno*3] */
int pno;
float plane[4]; /* a,b,c,d for plane agu.*/
{
int i;
int pass_no=0;
float x,y,z;
float * cfp;
for(i=0;i<pno;i++)
{
cfp = points + (i*3)
x = *cfp; y = *(cfp+1); z = *(cfp+2);
if ( (plane[0]*x+plane[1]*y+plane[2]*z+plane[3]) < EPSINO)
pass_no++;
}
return(pass_no);
}
八.
Trans(mat,no)
float *mat; /* matrix[no][no] */
int no;
{
int i,j,k,l;
float sum,minf;
float *p,*pt,*pk,*pi;
p =(float *) malloc(no*sizeof(float));
for(i=0;i<no;i++) /* sum up each row */
{
sum = 0.0;
pt = mat + i*no;
for(j=0;j<no;j++)
{
pt++;
sum += (*pt);
}
*(p+i) = sum;
}
for(i=0;i<no-1;i++)
{
minf=*(p+i); k=i
for(j=i+1;j<no;j++) /* seek for the index of mininum */
if (minf>p[j]) {k = j; minf = p[j];}
if (k!=i) /* exchange the rows */
{
ph= mat + (no+k);
pi= mat + (no*i);
for(l=0;l<no;l++) /* row k ( row i */
{
sum = *(pi+l);
*(pi+l) = *(pk+l);
*(ph+l) = sum;
}
sum = p[i]; p[i]=p[k]; p[k]=sum; /* p[k] ( p[i] */
}
} /* end of for i */
free(p);
}
九.
struct bintree
{
int ele;
struct bintree *left;
struct bintree *right;
}
binsort(a,n,p_tree); /* procedure START */
int *a; /* a[n] */
int n;
struct bintree * p_tree; /* p_tree[n] */
{
int i;
boolean greater;
float value;
struct bintree *p_tree1,*p_treesave;
for(i=0;i<n;i++)
{
p_tree[i].ele = a[i];
p_tree[i].left = NULL;
p_tree[i].right = NULL;
}
for(i=1;i<n;i++)
{
value = a[i];
p_tree1 = p_tree; /* root of bin_tree */
while(p_tree1 != NULL)
{
p_treesave = p_tree1;
if (greater = (p_tree1->ele > value))
p_tree1 = p_tree1->left;
else
p_tree1 = p_tree1->right;
}
if (greater)
p_treesave->left = p_tree+i; /* chained onto the tree */
else
p_treesave->right = p_tree+i;
}
}