深耕专业教研,探索前沿技术
信息技术来源:宁波市 2025 学年第二学期高考模拟考试

第 15 题

答案与解析

第(2)小题

参考答案

D

解题思路

函数在一趟循环中比较相邻影片,必要时交换;随后递归处理前n−1项,使比较范围逐次缩小。这是用递归控制趟数的冒泡排序。比较的是下标3所存的综合得分,左侧得分较低时交换,因此较低得分向右移动。

程序分析

if n < 2:            #语句1
    return b

当前待处理部分不足2项时,不需要再比较相邻元素,直接返回列表。这是递归的终止条件。

for i in range(n - 1):
    if b[i][3] < b[i + 1][3]:
        b[i], b[i + 1] = b[i + 1], b[i]

i从0增至n−2,逐对比较相邻影片;若左侧得分更低,就交换整条影片记录。每次比较后,较低得分留在右侧,继续参与下一次比较。因此一趟结束时,前n项中的最低得分被送到下标n−1的位置。

return fsort(b, n - 1)

本趟已确定末项的位置,递归只处理前n−1项,再将其中最低分送到该部分的末尾。如此逐步缩小范围,最终得到按综合得分从高到低排列的列表,各层直接返回递归所得列表。

选项分析

A

错误。交换条件是左侧得分小于右侧得分,一趟将最低分送到右端,最终按综合得分降序排列。

B

错误。比较字段b[i][3]是综合得分,上映时间对应下标1,未参与排序比较。

C

错误。若把比较方向改为i从n−2递减到0,一趟会把最高分送到左端,但递归仍缩小右边界、只处理前n−1项,两者不配合。例如按得分简记为[1,2,3]:首趟从右向左比较得到[3,1,2],下一趟只比较前两项,序列仍为[3,1,2],未排成降序。

D

正确。改为n<=0后,n=1时会多执行一次函数体,但range(0)为空,不会比较或访问相邻元素;随后调用fsort(b,0)并返回。因此只多一次递归调用,最终排序结果不变。

第(3)小题

参考答案
  1. lst[pre][4] = lst[p][4]

  2. seat == lst[p][2] and lst[p][3] > 1

  3. lst[p][3] = seat - lst[p][1]

程序分析

lst = [[0,0,0,0,1]]          #lst[0][4]指向头节点
for i in range(1,row+1):
    lst.append([i,1,tot,tot,i+1])   #构造链表,初始化每排可选座位区间
lst[-1][4] = -1

主程序用列表模拟链表,每个区间结点依次存储[排数,起始座位号,终止座位号,可选座位数,后继下标]。lst[0]是表头入口记录,lst[0][4]保存首个有效区间的下标;各结点下标4处保存后继下标,−1表示没有后继。初始化时,每排对应一个[1,tot]区间,各排依次连接。区间的逻辑顺序由这些链接决定。

for info in data:
    if info[3] == "购票":
        order_seat(info[1],info[2],lst)
    else:
        add_seat(info[1],info[2],lst)

data已按时间升序排列,程序依次处理购票、退票事件。购票时将info[1]的座位号和info[2]的排号传入order_seat,因此函数参数seat表示待购座位号,row表示本次购票的排号;主程序初始化时的row表示影厅总排数。

pre = 0
p = lst[pre][4]
while p != -1 and lst[p][0] != row:
    pre = p
    p = lst[p][4]

p从首个有效区间开始,沿lst[p][4]保存的后继下标查找。每轮先令pre = p,再令p = lst[p][4],使pre跟在p之前,保存当前结点的前驱下标。循环遇到目标排的第一个区间时停止。

while p != -1 and lst[p][0] == row:
    ...
    pre = p
    p = lst[p][4]

在目标排内依次检查区间,根据seat位于区间的哪个位置选择处理分支。末尾沿当前结点的后继继续扫描,直到到达链尾或进入其它排。一次购票只会落在一个有效区间中。

if seat == lst[p][1] and lst[p][3] == 1:
    ①
elif seat == lst[p][1] and lst[p][3] > 1:
    lst[p][1] = seat+1
    lst[p][3] -= 1

两个分支都要求seat等于区间起点,再按可选座位数是否为1分开处理。第二个分支已有的语句把起点改为seat+1,并将座位数减1,保留右侧的可选区间。

elif ②:
    lst[p][2] = seat-1
    lst[p][3] -= 1

该分支已有的语句将终点改为seat−1,并将可选座位数减1,起点保持不变。

elif seat > lst[p][1] and seat < lst[p][2]:
    right = lst[p][2]
    lst[p][2] = seat-1
    ③
    lst.append([row,seat+1,right,right-seat,lst[p][4]])
    lst[p][4] = len(lst)-1

seat严格位于区间内部时,right先保存原终点,原结点的终点改为seat−1,留下左半段。随后追加右半段[seat+1,right],座位数为right−seat,其后继先取原结点的后继。最后将原结点的后继改为新结点下标len(lst)−1,形成“左半段→右半段→原后继”的链接。

填空分析

①

空①所在分支对应区间中只有一个座位且该座位被购买的情况,需要从有效链表中删除当前结点。lst[pre][4]保存前驱的后继下标,lst[p][4]保存当前结点的后继下标;让前驱直接连接当前结点的后继,填写:

lst[pre][4] = lst[p][4]

删除首个有效结点时pre为0,这一语句更新表头入口;删除链尾时,原后继为−1,这一语句使前驱成为链尾。这里只修改链接,保留lst中的存储位置,避免其他结点下标改变。

②

该分支保留原起点,将终点改为seat−1且座位数减1,因此对应购买区间最右端的座位。单座位区间已由前面的分支处理,可同时写明本分支处理多个座位的情况:

seat == lst[p][2] and lst[p][3] > 1

③

执行到空③时,原结点的终点已变为seat−1,起点lst[p][1]不变,但座位数尚未更新。按“终点−起点+1”,左半段的数量为(seat−1)−lst[p][1]+1,因此填写:

lst[p][3] = seat - lst[p][1]

也可直接利用已更新的终点,写成lst[p][3] = lst[p][2] - lst[p][1] + 1。

第(1)小题

参考答案
  1. [1,4]

  2. [6,7]

  3. [9,10]

本小题按源试卷表格读取记录:四条记录的排数均为5,座位号依次为3、5、3、8。

初始时第5排的可选区间为[1,10]。购票时移除对应座位,退票时恢复对应座位,并与相邻可选区间合并。

时间 第5排的操作 操作后的可选座位区间
初始 全部可选 [1,10]
08:37 3号购票 [1,2]、[4,10]
08:50 5号购票 [1,2]、[4,4]、[6,10]
09:00 3号退票 [1,4]、[6,10]
09:12 8号购票 [1,4]、[6,7]、[9,10]

09:00恢复的3号连接左侧[1,2]和右侧[4,4],合并为[1,4];09:12购买8号后,[6,10]拆为[6,7]和[9,10]。此后至09:15没有新的记录,因此保留表中最后一行的区间。