实验2.数据结构综合实验
数据结构综合实验
本实验把列表、元组、字符串、集合、字典串起来,做一个班级花名册:既能增删查改,也能按标签筛选、按成绩排序、导出摘要。
实验目标
- 会用列表保存有序记录,会用
append、insert、remove、sort和列表生成式。 - 会用元组表示“不可拆改”的字段组合(如坐标式的一条固定信息)。
- 会用字符串方法清洗姓名、拼接输出、格式化对齐。
- 会用集合做去重和交并差,筛选“同时选修多门课”的学生。
- 会用字典按学号快速查找,并用字典生成式做统计。
数据约定
每名学生是一个字典,结构如下:
{
'id': 'S001', # 学号,字符串
'name': '张三', # 姓名
'scores': [90, 85, 78], # 三门课成绩,列表
'tags': {'数学', '篮球'} # 兴趣/课程标签,集合
}roster 是保存多条学生记录的列表。
参考实现
"""
班级花名册
覆盖:列表、元组、字符串、集合、字典
"""
# 1)准备数据:列表 + 字典 + 集合
roster = [
{
'id': 'S001',
'name': ' 张三 ',
'scores': [90, 85, 78],
'tags': {'数学', '篮球'},
},
{
'id': 'S002',
'name': 'Li Si',
'scores': [72, 68, 91],
'tags': {'英语', '篮球'},
},
{
'id': 'S003',
'name': '王五',
'scores': [55, 60, 58],
'tags': {'数学', '英语'},
},
{
'id': 'S004',
'name': '赵六',
'scores': [88, 92, 95],
'tags': {'数学'},
},
]
# 2)字符串清洗:去掉姓名两侧空白,英文统一首字母大写
for student in roster:
raw_name = student['name']
cleaned = raw_name.strip()
if cleaned.isascii():
cleaned = cleaned.title()
student['name'] = cleaned
# 3)列表方法:新增、查找、删除
new_student = {
'id': 'S005',
'name': '钱七',
'scores': [80, 80, 80],
'tags': {'篮球'},
}
roster.append(new_student)
# 按学号查找(字典键访问)
target_id = 'S002'
found = None
for student in roster:
if student['id'] == target_id:
found = student
break
print(f'查找 {target_id}:', found['name'] if found else '未找到')
# 删除指定学号的学生
remove_id = 'S003'
roster[:] = [s for s in roster if s['id'] != remove_id]
print(f'已删除 {remove_id},剩余 {len(roster)} 人')
# 4)平均分与排序:用列表生成式提取平均分,再按平均分降序
for student in roster:
student['average'] = sum(student['scores']) / len(student['scores'])
# 先算再排;用 sorted 生成新列表,不直接打乱原列表顺序
ranked = sorted(roster, key=lambda s: s['average'], reverse=True)
print('按平均分排名:')
for rank, student in enumerate(ranked, start=1):
# 字符串格式化与对齐
line = f"{rank}. {student['id']} {student['name']:<8} 平均分 {student['average']:.1f}"
print(line)
# 5)集合运算:同时有“数学”和“篮球”的学生
math_students = {s['id'] for s in roster if '数学' in s['tags']}
basketball_students = {s['id'] for s in roster if '篮球' in s['tags']}
both = math_students & basketball_students
print('同时选数学和篮球:', sorted(both))
print('只选数学:', sorted(math_students - basketball_students))
print('选了数学或篮球:', sorted(math_students | basketball_students))
# 6)字典生成式:学号 -> 平均分
avg_map = {s['id']: round(s['average'], 1) for s in roster}
print('学号平均分表:', avg_map)
# 7)元组:用不可变三元组导出“学号、姓名、平均分”
summary = tuple((s['id'], s['name'], round(s['average'], 1)) for s in ranked)
print('摘要(元组):', summary)
# 8)按分数段统计人数(字典 + 列表)
level_count = {'优秀': 0, '良好': 0, '及格': 0, '不及格': 0}
for student in roster:
avg = student['average']
if avg >= 90:
level_count['优秀'] += 1
elif avg >= 80:
level_count['良好'] += 1
elif avg >= 60:
level_count['及格'] += 1
else:
level_count['不及格'] += 1
print('分数段人数:', level_count)预期结果要点
清洗后姓名应为:张三、Li Si、王五、赵六、钱七(王五 在删除后不存在)。删除 S003 后剩 4 人。S002 的平均分约为 77.0。同时含“数学”和“篮球”的学号应只有 S001。
扩展挑战
- 用
zip把课程名列表['语文', '数学', '英语']和scores压成“课程-分数”字典。 - 用
str.split/str.join把标签集合导出成数学|篮球形式。 - 增加“按姓名模糊查找”:对
name做lower()后再用成员运算in判断。
知识点总结
- 列表:有序、可变;适合保存花名册本体和每人多门成绩;
append追加,列表生成式做过滤,sorted(..., key=lambda)排序而不必原地打乱。 - 元组:有序、不可变;适合把“一条摘要记录”冻结成
(id, name, avg),避免后续被误改。 - 字符串:
strip去空白,title/isascii处理英文名,{:<8}左对齐,f-string 做展示;字符串是序列,也可切片和in判断。 - 集合:无序、元素唯一;用
{...}字面量或集合生成式创建;&、|、-做交并差,非常适合“标签筛选”。 - 字典:键值对,按键 $O(1)$ 查找;学生记录用字典表达字段;
{k: v for ...}做映射统计;遍历常用items()。 - 嵌套结构:列表套字典、字典里的值再是列表/集合,是真实业务数据的常见形态;修改时要先定位到具体那条字典再改字段。
- 易错点:对元组用下标赋值会
TypeError;集合不能存列表等可变对象当元素;字典键不存在时用[]会KeyError(本实验用“先查找再使用”避免);sorted默认按字典对象比较会报错,必须写key。 - 学习重点:能根据“有序、可变、是否按键查找、是否需要去重”为每段数据选对容器,并完成一次跨容器的小型数据整理流程。