内容正文:
[时间:45分钟 满分:50分]
单元素养检测卷(五)(数据与数据结构 模块卷2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
一、选择题(本大题共12小题,每小题2分,共24分。在每小题给出的四个选项中,只有一个是符合题目要求的。)
1.下列关于数据结构的说法中,正确的是( )
A.用程序实现问题解决时只能采用一种数据结构
B.数据的逻辑结构是指数据元素间的关系
C.链表比数组更适合大量数据元素的随机访问
D.数组不必占用一片连续存储的单元
B
【解析】 选项A,程序实现可以采用多种数据结构,不是唯一的,选项错误;选项B,数据的逻辑结构指的是数据元素间的关系,选项正确;选项C,数组访问比链表高效,链表增加和删除比数组高效,选项错误;选项D,数组采用的是线性存储,需要占用连续的存储空间,选项错误。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2.有如下Python 程序段:
a=[1,5,9,2,6,8,3,4,7]
n=0;flag=True
for i in range(len(a)-1):
if a[i]<a[i+1] and flag==True:
n+=1;flag=False
elif a[i]>a[i+1] and flag==False:
n-=1;flag=True
print(n)
执行该程序段后,输出的值为( )
A.2 B.0
C.-1 D.1
【解析】 当a[i]<a[i+1] and flag==True成立时,则n+=1, flag=False;当a[i]>a[i+1] and flag==False成立时,则n-=1;flag=True;
a[i]:1,5,9,2,6,8,3,4,7
D
n:1,1,0,1,1,0,1,1
选项D正确。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
3.有如下Python程序段:
def ds(s,i):
if ”a”<=s[i]<=”z”:
s=s[:i]+s[i+1:]
elif ”0”<=s[i]<=”9”:
s=s[:i]+str((int(s[i])+6)%10)+s[i+1:]
return s
s=”Yy23mm4”;i=0
while i<len(s):
s=ds(s,i)
i+=1
print(s)
执行该程序段后,输出的s 的值为( )
A. ”Y89m0” B. ”Y29m0”
C. ”y23m4” D. ”89mm0”
B
【解析】 执行过程为:
i=0 Yy23mm4
i=1 Y23mm4
i=2 Y29mm4
i=3 Y29m4
i=4 Y29m0
选项B正确。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
4.一个底端封闭的圆柱形乒乓球收纳筒,最多可容纳4 个乒乓球,筒的直径只允许一个球进出。初始时,筒内自底向上已存有1、2 号球,依次放入顺序为3、4、5、6 号的4 个球,则取出所有乒乓球的顺序可能是( )
A.2,6,5,4,3,1 B.3,2,1,6,4,5
C.3,2,1,6,5,4 D.5,4,3,2,1,6
C
【解析】 栈是一种“后进先出”的数据结构。解出栈入栈问题时,要把握几个原则:(1)在入栈序列中顺序比出栈元素小的,必须是逆序。(2)在入栈序列中顺序比出栈元素大的,顺序无所谓。其次,乒乓球筒中最多容纳4 个乒乓球,这是本题较特殊的地方。选项A,若6 出栈,意味着栈内原有1,3,4,5,6号球, 与“最多可容纳4 个乒乓球”不符,选项错误;选项B,6 第4 个出栈,此时栈内剩余4,5,那到4,5 的出栈顺序应该是5,4,选项错误;选项D,5 第1 个出栈,意味着栈内有1,2,3,4,5 共五个乒乓球,选项错误。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
5.约定T 操作是指队列中1个元素出队后再入队,E操作是指将1个元素入队,P 操作是指队列中1个元素出队,队首指针head 和队尾指针tail 初始值均为0。则经过EETPETEP操作后,队首指针head 和队尾指针tail的值分别为( )
A.3和4 B.3和5 C.4和5 D.4和6
【解析】 根据题意,T为出队后入队(head和tail都要+1),E为入队(tail+1),P为出队(head+1)。head=tail=0,经过EETPETEP操作后,head 加四次,tail加六次,故head=4,tail=6,选项D正确。
D
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
6.二叉树的中序遍历序列为“BAEDFC”,后序遍历序列为“BEFDCA”,其前序遍历序列为( )
A.ABDEFC B.ABDCEF
C.ABCDEF D.ABCDFE
【解析】 根据二叉树的中序遍历序列和后序遍历序列可知,该二叉树的形状如图所示,因此可知其前序遍历序列为:ABCDEF,选项C正确。
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
7.某二叉树的数组表示示意图如下,该二叉树的后序遍历序列为( )
A.BAFDCGE B.BFDGECA
C.BFGDECA D.DEBFGCA
【解析】 根据该二叉树的数组实现,可以绘制出如下所示的二叉树,由此图可知该二叉树的后序遍历序列为:BFDGECA,
选项B正确。
B
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
8.[2023·金华一中检测]有如下Python程序段:
m=3
lst=[7,3,4,3,1,6,3]
for i in range(len(lst)-1):
for j in range(len(lst)-1,i,-1):
if lst[j]<lst[j-1]:
lst[j],lst[j-1]=lst[j-1],lst[j]
break
执行该程序段后,加框处语句被执行的次数是( )
A.3 B.4 C.5 D.6
【解析】 该程序的功能是利用排序(升序)求前4名,当第4名有并列时也保留;当i<3时(i为0,1,2),if语句被执行,但i>=m条件不成立,执行次数为3次;当i=3时,lst[i]!=lst[i-1]不成立,执行次数加1;当i=4时,条件成立,循环结束。所以被执行的次数为5次。选项C正确。
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
9.有如下Python 程序段:
def f(s):
if len(s)==1:
return True
elif len(s)==2:
return s[0]==s[1]
elif s[0]==s[-1]:
return f(s[1:-1])
else:
return False
print(f(”1234321”))
执行该程序段后,下列说法正确的是( )
A.输出的结果为False B.函数f()运用了迭代算法
C.函数f()的调用次数为4 D.函数f()的时间复杂度为O(n2)
C
【解析】 根据代码,这是利用递归判断一个字符串是否是“回文串”。选项A,”1234321”是“回文串”应该输出True,选项错误;选项B,运用了递归算法,选项错误;选项C,f(”1234321”)→f(”23432”)→f(”343”)→f(”4”)→True,调用4次,选项正确;选项D,根据以上分析,算法的时间复杂度是O(n),选项错误。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
10.下列Python 程序段的功能是在链表link1 中删除数据为key 的所有节点,link1 链表中的每个节点由一
个数据域和一个指针域组成。
#建立链表link1,代码略
key=int(input(”输入要删除的数据: ”))
head=0
while link1[head][0]==key and head!=-1:
head=link1[head][1]
p=q=head
if head==-1:
print(”全部数据删除”)
else:
q=link1[q][1]
while ①____________:
if link1[q][0]==key:
②____________
else:
p=link1[p][1]
q=link1[q][1]
则①、②处填入的代码分别为( )
A.①link1[q][1]!=-1 ②link1[p][1]=link1[q][1]
B.①link1[q][1]!=-1 ②link1[q][1]=link1[p][1]
C.①q!=-1 ②link1[q][1]=link1[p][1]
D
D.①q!=-1 ②link1[p][1]=link1[q][1]
【解析】 该程序段的功能是在链表link1 中删除数据为key 的所有节点,link1链表中的每个节点由一个数据域和一个指针域组成。程序通过while 循环找到第一个数据域为key 的节点,并将head 指向该节点的下一个节点,如果链表中所有节点的数据域都为key,则head 的值为-1。在while 循环中,程序首先判断当前节点的数据域是否为key,如果是,则删除当前节点,即将p节点的指针域指向q 节点的指针域,如果不是,则将p 指向下一个节点,q 也指向下一个节点。最后,程序通过while 循环遍历链表并输出每个节点的数据域。选项D正确。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
11.有如下Python 程序段:
import random
d=[28,37,39,42,45,50,70,80]
i,j,n=0,len(d)-1,0
key=random.randint(20,35)*2
while i<=j:
m=(i+j)//2; n+=1
if key==d[m]:
break
elif key<d[m]:
j=m-1
else:
i=m+1
print(i,j,m,n)
执行该程序段后,下列说法正确的是( )
A.n 的值可能为4
B.若n 的值为2,则必定满足i<=j
C.m 的值可能为1
D.若n 的值为3,则key 的值可能是45
【解析】 key 是[40,70]区间的偶数,n 是循环次数,也是二分查找次数。列表d 中有8 个元素,3 层满二叉树的节点个数是7,如果n<3,说明循环一定被提前中断了(break),所以必定满足i<=j。选项A,由于key<
B
=70、m=(i+j)//2(中点取值偏左),n<=3,选项错误;选项C,m==1 时,查找区间还有3 个元素:[28,37,39],d[1]==37,不可能和key 相等,接下来无论j=1-1或i=1+1(根据key 的范围,应该执行i=1+1),下标1 肯定不在接下来要查找的区间了,所以最后m 不可能为1,选项错误;选项D,key 不可能是45,选项错误。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
12.有如下Python程序段:
import random
q=[1]*12;head=0;tail=1;s=0
k=random.randint(1,5)
while k>0:
q[tail]=q[head]*2
tail+=1
q[tail]=q[head]*2+1
tail+=1;head+=1;k-=1
while head<tail:
s+=q[head]
head+=1
执行该程序段后,s的值不可能是( )
A.7 B.22
C.35 D.51
A
【解析】 本题考查随机数和队列及其代码实现知识。队首head 的初值为0,队尾tail 的初值是1,由代码可知变量k的值是1~5 之间的整数,而变量s 的作用是将队列中的数据进行求和。若k=1,循环进行一次,模拟后可知,head=1,tail=3,s=2+3=5。为方便讨论,列出k 的各种可能,如下表所示:
根据上表可知,s的值不可能为7,选项A符合题意。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
二、非选择题(本大题共3小题,第13题8分,第14题9分,第15题9分,共26分)
13.图书查询。所有正版图书均有唯一的国际标准书号(ISBN),ISBN 由13 位数字和字符“——”组成,字符“——”对数字间隔分段。如:某图书的ISBN 为“978——7——5536——3176——9”(其中“978”表示图书类代码,“7”表示地区码,“5536”表示出版社代码,“3176”表示书序码,“9”为校验码)。小李为某校园书吧编写了图书查询的Python程序。
请回答下列问题。
(1)主程序
lst1=readfile(”in.csv”)# 校园书吧库存图书信息存储在文件“in.csv”中
while True:
print(”1.验证ISBN 校验码; 2.统计出版社费用; 3.操作结束”)
opt=int(input(”请输入操作编号(1~3): ”))
if opt==1:
isbn=input(”请输入ISBN 号: ”)
if check(isbn):
print(”校验码正确”)
else:
print(”校验码错误”)
elif opt==2:
code=input(”请输入出版社代码: ”)
money=total(code)
print(”书吧中该出版社出版的图书总价: %.2f 元”%money) #
输出的总金额保留2 位小数点
else:
print(”操作结束”)
break
执行该程序,若输入opt 值为4,则程序将_____________(单选,填字母:A.运行时报错/ B.输出“操作结束”)。
(2)读写文件
小李将校园书吧库存图书信息存储在文件“in.csv”中,内容如下图所示。readfile()函数用于逐行读取文件数据存入列表并返回。请在横线处填入
B (2分)
合适的代码。
import pandas as pd
defreadfile(filename): # 读取CSV文件内容,将其存入列表并返回
df1=pd. read_csv(filename, encoding=”GBK”)
lst=[]
for i in df1.index:
isbn=df1[”ISBN”][i]
num=df1[”图书数量”][i]
price=df1[”单价(元)”][i]
lst.append([isbn,num,price]) # 添加到列表
return _____________#
(3)校验码验证
ISBN 最后一位的校验码用来检验前面12位数字是否准确,是保护知识产权的一种检验方法。计算方法如下:
lst (2分)
①将ISBN 中前12 位数字从左到右依次编号为“1,2,3,…,12”;
②若数字编号是奇数,则对应权值为1,否则权值为3。首先将ISBN 中前12 位的数字值与对应权值相乘,然后将计算所得值进行累加;
③最后,用 10 减去第②步结果对10整除的余数,所得结果即为校验码。
请在横线处填入合适的代码。
def check(ISBN): #对ISBN 校验码验证
n=len(ISBN)
val=0;k=3
for i in range(0,n-1):
if '0'<=ISBN[i]<='9':
k=4-k
val+=int(ISBN[i])*k
_______________________________#
if result==int(ISBN[-1]):
return True
else:
result=10-val%10 (2分)
return False
(4)统计校园书吧中某出版社出版的所有图书总价。请在横线处填入合适的代码。
'''
列表lst1 中的部分数据如:[['978-7-5139-3066-6',7,59.80],['978-7-5063-3174-6',9,48.00],…]
'''
def total(code): #统计书吧中出版社代码为code 的所有图书总价
n=len(lst1)
money=0
for i in range(n):
isn=lst1[i][0].split('-') # 将字符串list1[i][0]以“-”为分隔符,分
割成多个字符串组成的列表
if isn[2]==code:
___________________________________________________
_________________________#
money=money+lst1[i][1]*lst1[i][2] 或money+=
lst1[i][1]*lst1[i][2] (2分)
return money
【解析】 (1)通过特殊测试数据考查学生对代码调试和分支结构的理解。若输入opt 的值为4,模拟程序运行过程,将选择else 分支,此时输出内容为“操作结束”,答案选B。
(2)考查学生根据函数功能描述,阅读理解程序代码的能力。根据函数功能描述,结合程序代码,可知readfile 函数将读取CSV 文件内容,同时将文件内容存储到列表lst 中,最后返回lst 列表,答案为:lst。
(3)考查学生对ISBN 校验码算法步骤实现的处理能力,要求学生根据
算法步骤描述理解代码,同时具有代码实现能力。依据算法中第③步的描述,该算法步骤实现语句为:result=10-val%10。
(4)本题考查学生在具体情景中对二维列表的综合应用能力。通过枚举算法枚举列表lst1 中所有图书信息lst1[i],提取ISBN(lst1[i][0])中的出版社代码并进行判断。根据lst1[i]中存储的图书信息,找到对应图书数量(lst1[i][1])和单价(元)(lst1[i][2]),然后计算该出版社总费用,同时累加到变量money 中。因此,答案为:money=money+lst1[i][1]*lst1[i][2]。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
14.程序运行时,以内存单元为基本单位对内存进行分配,若干个连续的内存单元称为一个内存块,每个内存块的信息包含首地址和大小。其方法描述如下:
(1)初始化空闲内存块。将信息存储在链表flink 中。
(2)分配大小为size 的内存。先依次查找链表flink 中是否存在不小于size 的内存块。若存在且等于size,则将其从链表flink 中删除;若存在且大于size,则修改该内存块的信息;若不存在,则对不连续的空闲内存块按顺序进行分配;若空闲内存块之和小于size,则分配失败。
(3)释放内存。将释放的内存块信息插入链表flink,链表flink 各节点按首地址从小到大排列。如果释放的内存块与链表中的某个内存块相邻,则将它们合并成一个更大的内存块。
请回答下列问题。
(1)初始空闲内存块大小为16,进行两次分配和一次释放的过程如下图所示。若继续分配大小为8 的内存块,____________(选填:能/不能)成功。
能 (1分)
①初始化空闲内存块,大小为16。
②第1 次分配,大小为4,分配后空闲12。
③第2 次分配,大小为8,分配后空闲4。
④释放第1 次分配的内存,释放后空闲8(不连续)。
(2)定义如下allocate(flink,head,size)函数,参数flink 是空闲内存块链表,head 是flink 的头指针,size 为所需内存块大小。函数功能为分配size 大小的空闲内存块,并返回分配的内存块信息及头指针head。请在横线处填入合适的代码。
def allocate(flink, head, size):
block=[]
pre=head
cur=head
while cur!=-1:
if flink[cur][1]>=size:
break
pre=cur
①__________________________
if cur!=-1 and flink[cur][1]==size:
block.append([flink[cur][0],size])
if pre==cur:
head=flink[cur][2]
else:
②____________________________________
elif cur!=-1 and flink[cur][1]>size:
cur=flink[cur][2] (2分)
flink[pre][2]=flink[cur][2] (2分)
block.append([flink[cur][0],size])
flink[cur][0]=flink[cur][0]+size
flink[cur][1]=flink[cur][1]-size
if len(block)==0:
#对不连续的空闲内存块按顺序进行分配,如果空闲内存块之和仍 小于size,则分配失败,代码略
return block,head
(3)实现模拟过程及内存释放的部分Python 程序如下,请在横线处填入合适的代码。
def release(flink,head,block):
for i in range(len(block)):
if head==-1:
flink.append([block[i][0],block[i][1],-1])
head=len(flink)-1
else:
pre=head
cur=head
while cur!=-1 :
if flink[cur][0]>block[i][0]:
break
pre=cur
cur=flink[cur][2]
flink.append([block[i][0],block[i][1],cur])
if ①______________________:
pre=len(flink)-1
head=len(flink)-1
else:
flink[pre][2]=len(flink)-1
cur=flink[pre][2]
#合并相邻的空闲块
cur==head (2分)
while cur!=-1:
if flink[pre][0]+flink[pre][1]==flink[cur][0]:
②___________________________________
flink[pre][2]=flink[cur][2]
cur=flink[cur][2]
continue
pre=cur
cur=flink[cur][2]
flink[pre][1]+=flink[cur][1](2分)
return [[-1,-1,-1]],head
flink=[[0,16,-1]] # 初始化空闲内存块链表,0:起始地址,16:长度
head=0
block1,head=allocate(flink ,head, 4)
block2,head=allocate(flink, head, 8)
block1,head=release(flink,head,block1)
【解析】 (1)根据描述,此时有二块大小都是4 的内存块,要求分配大小为8 的内存块,刚好可以满足要求。
(2)①此处遍历链表,查找空闲内存块中不小于size 的位置。遍历的基本代码:cur=flink[cur][2];②根据条件flink[cur][0]==size,说明空闲内存块的大小和要求的size 相等,要将当前空闲内存块从链表删除:flink[pre][2]=flink[cur][2]。
(3)①内存块释放,要在flink 中增加相应的节点。增加节点有二种情况:在第一个节点之前插入或在其他节点之后插入。根据后面的代码,修改
了头指针(head=len(flink)-1),说明当前释放的内存块起始地址是最小的,前面遍历链表的代码执行一次就break 了,没有执行cur=flink[cur][2]。所以这里的条件是:cur==head;②根据条件,这里是二个空闲内存块位置相邻,要将二个空闲内存块合并为一个。根据后面的代码,缺少了修改容量的代码,要将容量修改为二者容量之和:flink[pre][1]+=flink[cur][1]。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
15.操作系统管理n 个连续的内存块,地址编号为0~n-1,可动态分配给多项作业使用。现有一个作业队列,其中记录了各项作业申请的内存块大小、作业请求等情况。某作业执行时,会向系统请求分配一段连续的内存块,执行完后由系统回收该空闲内存块(回收后若存在连续的多个空闲内存块,则合并为一块)。系统分配内存块的方法是:按作业请求从所有空闲内存块中尽可能地挑选一个能满足要求的最小空闲内存块。当有多块满足要求时,选择起始地址编号最小的空闲内存块(能分配时则从该空闲内存块的起始地址开始分配,不能分配时则提示内存不足)。
请回答下列问题。
(1)设有500 个内存块,地址编号为0~499,初始全部为空闲内存块。某队列作业顺序执行情况如下图所示,则作业“J6”申请到的内存块起始地址编号为_____________。
224 (1分)
(2)定义如下函数sortbysize(free),参数free 链表的各节点由空闲内存块的起始地址、块大小、链接地址描述,并按起始地址升序排列。函数功能是保持free 的链接结构不变,返回列表lst,lst 是free 中各节点按块大小升序、块大小相同按起始地址升序排列的索引序列。
def sortbysize(free):
#对链表free 进行排序,free[0]描述了链表的头指针、空闲内存块个数
lst=[]
p=free[0][0] #free[0][0]为链表的头指针
while p!=-1:
lst.append(p) #为lst 追加一个元素
p=free[p][2]
m=free[0][1] #free[0][1]为空闲内存块个数
stk=[-1]*m;top=-1
j=m-1
while j>=0:
tmp=lst[j]
while top!=-1 and free[tmp][1]>free[stk[top]][1]:
lst[j]=stk[top];j+=1;top-=1
top+=1;stk[top]=tmp;j-=1
while top>-1:
j+=1;lst[j]=stk[top];top-=1
return lst
执行语句lst=sortbysize([[1,4],[0,160,2],[200,120,3],[350,70,4],[442,70,-1]]),执行过程中变量top 的值最大为_____,执行
3
后lst 的值为_______________________。
(3)实现内存分配功能的Python程序如下,请在横线处填入合适的代码。
def alloc(size, free): #分配内存,无法分配时返回-1,否则返回分配内存块的起始地址
#检查free 链表,若有地址连续的多个空闲内存块则合并为一个空闲内
存块,代码略
if free[0][1]==0: #free[0][1]为空闲内存块个数
return-1
[3,4,2,1](2分)
lst=sortbysize(free)
i=0
while i<len(lst) and ①__________________________:
i+=1
if i==len(lst):
return-1
prev=0
curr=free[0][0] #free[0][0]为链表的头指针
free[lst[i]][1]<size(2分)
while curr!=lst[i]:
prev=curr
curr=free[curr][2]
②____________________________________________________
if free[curr][1]==size: #分配空闲内存块,并更新链表free
if prev!=0:
free[prev][2]=free[curr][2]
else:
address=free[curr][0]或address=free[lst[i]][0](2分)
free[prev][0]=free[curr][2]
free[0][1]-=1
else:
③_____________________________
free[curr][1]-=size
return address
'''
读取并处理作业队列,free 链表的各节点由空闲内存块的起始地址、块
free[curr][0]+=size(2分)
大小、链接地址描述,并按起始地址升序,代码略。若当前作业需要分配size 大小的内存块,则进行如下处理:
'''
address=alloc(size,free)
if address==-1:
print(”无法分配,内存不足! ”)
else:
print(address)
【解析】 (1)可以画数轴或列出当前的“块”来思考。作业J1~J4 的内存依次分配为[0,159],[160, 223],[224,343],[344, 429],最后剩余空闲内存[430, 499],长度为69。随着作业J1 和J3 的回收,最小存放长度为70 的块是原作业J3 的内存,即起始编号224。
(2)要求从代码中读懂算法,当然在数据量不大的情况下也可以手动模拟。根据题意排序后的结果是一个索引序列,排序规则是按块大小升序、起始地址升序,则lst=[3,4,2,1]。执行过程中辅助栈的最大元素个数是3。实际上这是双栈模拟排序算法,模拟排序时牢记两个原则:“原始栈当前元素个数+辅助栈当前元素个数=总元素个数”;“维护一个
降序的辅助栈”具体模拟过程不做展开。
(3)实现具体的内存分配。由于lst 是已排序的空闲内存起始位置索引列表,从头开始遍历列表lst,保证找到最小的可容纳长度为size 的空闲内存,即第①问答案free[lst[i]][1] <size。
第②问初始化address,由于if 语句的特性只执行一个分支,即返回值address 可能未被赋值,所以需要提前对address 赋值,address=free[curr][0],即当前空闲内存的起点。将该长度为size 的内存分配给新的作业后,这部分空闲内存减少了size 长度,即起点后移size,第③问答案free[curr][1]+=size。
感谢聆听,再见!
$$