Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第11章 数据结构:字典

引言

想象一下,你在学校里有一个储物柜。每个储物柜都有一个编号,你可以在里面放东西。要用储物柜,你需要记住你的柜子号码,这样就能快速找到你的东西。

或者想想你查字典的时候:你想找“苹果“这个词,你会先找拼音“p“,然后在这个字母下面找“ping“,最后找到“苹果“。这个过程就是通过“索引“(拼音)来找到“内容“(解释)。

在Python中,有一种和储物柜很像的数据结构,叫做“字典“(Dictionary)。字典让我们能够用“钥匙“(key)来找到对应的“值“(value),就像用储物柜的号码来找到里面的东西一样。

🎯 本章学习目标

  • 学会使用字典存储“键-值“对数据
  • 理解字典和数学中“映射“的关系
  • 了解字典为什么查找速度这么快(哈希表)
  • 用字典解决实际问题

给家长的小贴士 🧑‍🏫

生活类比:可以用以下例子帮助孩子理解“键-值“对:

  • 电话簿:姓名→电话号码
  • 字典查词:拼音→词语解释
  • 储物柜:柜号→存放物品
  • 身份证号:号码→个人信息
  • 快递柜:取件码→快递包裹

数学关联:字典的概念和数学中的“映射“或“函数“非常相似!如果孩子学过函数 y = f(x),可以告诉孩子:

  • 键(key)就是自变量 x
  • 值(value)就是因变量 y
  • 字典就是一组特殊的函数关系

什么是字典

字典是Python中的一种数据结构,它存储的是“键-值“对(key-value pairs)。

键和值的概念

  • 键(key):就像储物柜的编号,用来唯一标识一个值
  • 值(value):就像储物柜里放的东西,是我们真正想要存储的数据

数学中的“映射“ 📊

在数学课中,你可能学过映射或者函数的概念。比如:

  • 如果 x = 1,那么 y = 2
  • 如果 x = 2,那么 y = 4
  • 如果 x = 3,那么 y = 6

这可以写成函数:y = 2x

在Python的字典中,我们也可以表达类似的关系:

# 创建一个字典
heights = {"小明": 150, "小红": 145, "小华": 152}

# 访问字典中的值
print(heights["小明"])  # 输出: 150

在这个例子中:

  • “小明”、“小红”、“小华” 是键(key),就像数学中的 x
  • 150、145、152 是值(value),就像数学中的 y
  • 整个 {"小明": 150, "小红": 145, "小华": 152} 就是一组映射关系

给家长的小贴士 🧑‍🏫

数学融入:可以和孩子一起做以下练习:

  1. 让孩子写出班级同学的姓名和身高的对应关系
  2. 问问孩子:这像不像数学中的“有序数对“?
  3. 引导孩子理解:(姓名, 身高) 就像 (x, y) 这样的坐标

思考问题

  • 如果两个同学叫同一个名字,会发生什么?(引导学生理解键的唯一性)
  • 如果想查询某个同学的身高,需要做什么?(引导学生理解查找的概念)

字典与列表的区别

特点列表字典
索引数字索引(0, 1, 2…)任意不可变类型的键
访问list[0]dict["key"]
顺序有序无序(Python 3.7+有序)
用途按顺序存储数据按键值对存储数据

给家长的小贴士:可以告诉孩子,列表像是一排编号的盒子,你必须记住号码才能找到东西;而字典像是给每个盒子贴了标签,你可以直接通过标签找到东西。


为什么字典查找这么快?⚡

你可能会问:列表和字典都可以存储数据,为什么字典的查找速度更快呢?

列表的查找方式

想象一下,你要在一本没有索引的书中找某个词。你必须:

  1. 从第一页开始
  2. 一页一页地翻
  3. 直到找到这个词

如果书有100页,你平均要翻50页才能找到!

在Python中,用列表查找也是这样:

# 用列表存储学生信息
students_list = ["小明", "小红", "小华", "小刚", "小李"]

# 查找"小华"
if "小华" in students_list:
    print("找到了!")
# Python需要从第一个开始,一个一个比较,直到找到"小华"

字典的查找方式:哈希表 🗂️

字典使用了一种叫做哈希表(Hash Table)的技术,它就像给每个数据都贴了一个“魔法标签“。

什么是哈希函数?

哈希函数就像一个“魔法计算器“,它能:

  • 把任意输入(比如“小明“)转换成一个数字(比如 23)
  • 相同的输入总是得到相同的数字(“小明“永远是23)
  • 不同的输入大概率得到不同的数字
# 简化版的哈希函数(用取余数来模拟)
def simple_hash(key, size):
    """简化版哈希函数:把字符串转成数字,然后取余"""
    # 在真实Python中,hash()函数要复杂得多
    total = 0
    for char in key:
        total += ord(char)  # 把字符转成数字
    return total % size

# 假设我们有10个"盒子"
print(simple_hash("小明", 10))  # 输出: 某个0-9的数字
print(simple_hash("小红", 10))  # 输出: 另一个0-9的数字

哈希表的工作原理

想象你有100个储物柜,编号0-99:

  1. 添加数据时

    • 把“小明“通过哈希函数计算,得到 23
    • 把“小明“的信息放在第23号柜子
    • 把“小红“通过哈希函数计算,得到 57
    • 把“小红“的信息放在第57号柜子
  2. 查找数据时

    • 要找“小明“,用哈希函数计算,得到 23
    • 直接去第23号柜子拿
    • 不需要一个个柜子翻!

数学类比:余数的妙用 ➗

哈希函数的核心思想很像“取余数“运算:

问题:有100个苹果,要分给7个人,每人几个?怎么分配?

# 用取余数来分配
apples = ["苹果1", "苹果2", "苹果3", ..., "苹果100"]
people = 7

for i, apple in enumerate(apples):
    person = i % people  # 0, 1, 2, 3, 4, 5, 6, 0, 1, 2, ...
    print(f"{apple} 给第{person}个人")

哈希函数也是类似的思路:把数据通过计算“分配“到不同的位置。

给家长的小贴士 🧑‍🏫

讲解方式

  1. 用快递柜做类比

    • 快递柜有100个格子
    • 你收到取件码“23-5678“
    • 你直接去23号柜子,输入5678就能取件
    • 不需要一个个柜子试!
  2. 时间复杂度(适合有编程基础的家长):

    • 列表查找:O(n),n是元素个数
    • 字典查找:O(1),和元素个数无关
    • 如果有100万个数据,列表平均要找50万次,字典只需要1次!
  3. 实际演示

import time

# 创建大数据
big_list = list(range(100000))
big_dict = {i: f"value_{i}" for i in range(100000)}

# 测试列表查找
start = time.time()
result = 99999 in big_list
list_time = time.time() - start

# 测试字典查找
start = time.time()
result = 99999 in big_dict
dict_time = time.time() - start

print(f"列表查找时间: {list_time:.6f}秒")
print(f"字典查找时间: {dict_time:.6f}秒")
print(f"字典快了 {list_time / dict_time:.0f} 倍!")

注意事项

  • 哈希表虽然快,但需要更多内存空间
  • 不是所有情况都需要字典,数据量小时用列表就够了
  • 小学阶段不需要深入理解哈希算法,知道“它能快速定位“即可

创建字典

方法一:直接创建

# 创建一个空字典
empty_dict = {}

# 创建一个有内容的字典
student = {"name": "小明", "age": 12, "grade": 6}

方法二:使用dict()函数

# 使用dict()函数创建
student = dict(name="小明", age=12, grade=6)

print(student)
# 输出: {'name': '小明', 'age': 12, 'grade': 6}

给家长的小贴士:这两种方法创建的字典是一样的,第一种方法更常用,特别是在处理复杂数据结构时。


访问字典中的值

使用键访问值

scores = {"语文": 95, "数学": 98, "英语": 88}

# 访问语文成绩
print(scores["语文"])  # 输出: 95

# 访问数学成绩
print(scores["数学"])  # 输出: 98

处理键不存在的情况

如果我们访问一个不存在的键,程序会报错:

scores = {"语文": 95, "数学": 98, "英语": 88}

# 这行代码会报错!KeyError
print(scores["科学"])

为了避免这种情况,我们有两种方法:

方法1:使用in检查键是否存在

scores = {"语文": 95, "数学": 98, "英语": 88}

subject = "科学"
if subject in scores:
    print(scores[subject])
else:
    print(f"没有{subject}这门课的成绩")

方法2:使用get()方法

scores = {"语文": 95, "数学": 98, "英语": 88}

# 使用get方法,如果键不存在,返回None
print(scores.get("科学"))  # 输出: None

# 使用get方法,如果键不存在,返回默认值
print(scores.get("科学", "没有这门课"))  # 输出: 没有这门课

给家长的小贴士get()方法更安全,建议孩子养成使用get()的习惯,特别是在处理用户输入时。


添加和修改字典元素

添加新的键值对

# 创建一个空字典
phone_book = {}

# 添加新的联系人
phone_book["小明"] = "123-4567"
phone_book["小红"] = "234-5678"

print(phone_book)
# 输出: {'小明': '123-4567', '小红': '234-5678'}

修改现有的值

scores = {"语文": 95, "数学": 98, "英语": 88}

# 修改语文成绩
scores["语文"] = 99

print(scores)
# 输出: {'语文': 99, '数学': 98, '英语': 88}

给家长的小贴士:在Python中,添加新元素和修改现有元素的语法是一样的。如果键不存在,就是添加;如果键已存在,就是修改。


删除字典元素

方法1:使用del语句

scores = {"语文": 95, "数学": 98, "英语": 88}

# 删除语文成绩
del scores["语文"]

print(scores)
# 输出: {'数学': 98, '英语': 88}

方法2:使用pop()方法

scores = {"语文": 95, "数学": 98, "英语": 88}

# 删除并返回数学成绩
math_score = scores.pop("数学")
print(math_score)  # 输出: 98
print(scores)       # 输出: {'语文': 95, '英语': 88}

方法3:使用popitem()方法

scores = {"语文": 95, "数学": 98, "英语": 88}

# 删除并返回最后一个键值对(Python 3.7+)
last_item = scores.popitem()
print(last_item)  # 输出: ('英语', 88)
print(scores)     # 输出: {'语文': 95, '数学': 98}

给家长的小贴士:提醒孩子,del语句直接删除,不会返回值;pop()方法会返回被删除的值,可以在需要使用这个值的时候使用。


字典的常用操作

获取所有键、所有值、所有键值对

scores = {"语文": 95, "数学": 98, "英语": 88}

# 获取所有键
print(scores.keys())    # 输出: dict_keys(['语文', '数学', '英语'])

# 获取所有值
print(scores.values())  # 输出: dict_values([95, 98, 88])

# 获取所有键值对
print(scores.items())   # 输出: dict_items([('语文', 95), ('数学', 98), ('英语', 88)])

获取字典的长度

scores = {"语文": 95, "数学": 98, "英语": 88}

print(len(scores))  # 输出: 3

检查键是否存在

scores = {"语文": 95, "数学": 98, "英语": 88}

# 使用in检查
print("语文" in scores)   # 输出: True
print("科学" in scores)   # 输出: False

# 使用not in检查
print("语文" not in scores)  # 输出: False

清空字典

scores = {"语文": 95, "数学": 98, "英语": 88}

# 清空字典
scores.clear()

print(scores)  # 输出: {}

给家长的小贴士keys()values()items()返回的是视图对象,不是列表。如果需要列表,可以用list()转换:list(scores.keys())


遍历字典

遍历所有键

scores = {"语文": 95, "数学": 98, "英语": 88}

# 方法1:直接遍历字典(遍历的是键)
for subject in scores:
    print(subject)

# 输出:
# 语文
# 数学
# 英语

# 方法2:使用keys()方法(更明确)
for subject in scores.keys():
    print(subject)

遍历所有值

scores = {"语文": 95, "数学": 98, "英语": 88}

for score in scores.values():
    print(score)

# 输出:
# 95
# 98
# 88

遍历所有键值对

scores = {"语文": 95, "数学": 98, "英语": 88}

# 使用items()方法同时获取键和值
for subject, score in scores.items():
    print(f"{subject}: {score}分")

# 输出:
# 语文: 95分
# 数学: 98分
# 英语: 88分

给家长的小贴士:最常用的是items()方法,因为它能同时获取键和值,代码更简洁。


字典的常用方法

update()方法 - 更新字典

# 原字典
scores = {"语文": 95, "数学": 98}

# 新数据
new_scores = {"英语": 88, "数学": 100}

# 用new_scores更新scores
scores.update(new_scores)

print(scores)
# 输出: {'语文': 95, '数学': 100, '英语': 88}

setdefault()方法 - 设置默认值

scores = {"语文": 95, "数学": 98}

# 如果"英语"不存在,设置默认值85
english_score = scores.setdefault("英语", 85)
print(english_score)  # 输出: 85
print(scores)         # 输出: {'语文': 95, '数学': 98, '英语': 85}

# 如果"数学"已存在,不会修改
math_score = scores.setdefault("数学", 0)
print(math_score)     # 输出: 98
print(scores)         # 输出: {'语文': 95, '数学': 98, '英语': 85}

fromkeys()方法 - 创建相同值的字典

# 创建一个字典,所有值都是0
subjects = ["语文", "数学", "英语"]
scores = dict.fromkeys(subjects, 0)

print(scores)
# 输出: {'语文': 0, '数学': 0, '英语': 0}

copy()方法 - 复制字典

original = {"语文": 95, "数学": 98}

# 浅复制
copied = original.copy()

# 修改复制的字典
copied["英语"] = 88

print(original)  # 输出: {'语文': 95, '数学': 98}
print(copied)    # 输出: {'语文': 95, '数学': 98, '英语': 88}

给家长的小贴士copy()方法很重要,因为它创建了一个独立的副本,不会影响原字典。直接赋值new_dict = old_dict只是创建了一个引用。


字典的键的要求

字典的键必须满足以下要求:

  1. 键必须是不可变类型

    • 可以是:整数、浮点数、字符串、元组
    • 不能是:列表、字典
  2. 键必须是唯一的

    • 如果有重复的键,后面的值会覆盖前面的值
# 正确的键
dict1 = {1: "one", 2.5: "two point five", "hello": "world", (1, 2): "tuple key"}

# 错误的键(会报错)
# dict2 = {[1, 2]: "list key"}  # TypeError: 列表不能作为键

# 重复的键(后面的值会覆盖前面的)
dict3 = {"name": "小明", "name": "小红"}
print(dict3)  # 输出: {'name': '小红'}

给家长的小贴士:可以用“门牌号“来类比,门牌号是固定的、唯一的,就像字典的键。如果两个储物柜号码相同,就会造成混乱。


嵌套字典

字典的值可以是任意类型,包括另一个字典。这就是“嵌套字典“。

简单的嵌套字典

# 存储学生信息
student = {
    "name": "小明",
    "age": 12,
    "address": {
        "city": "北京",
        "district": "朝阳区"
    }
}

# 访问嵌套字典
print(student["address"]["city"])  # 输出: 北京

复杂的嵌套字典

# 存储多个学生的信息
students = {
    "001": {
        "name": "小明",
        "age": 12,
        "scores": {"语文": 95, "数学": 98}
    },
    "002": {
        "name": "小红",
        "age": 11,
        "scores": {"语文": 92, "数学": 99}
    }
}

# 访问小红的数学成绩
print(students["002"]["scores"]["数学"])  # 输出: 99

字典和列表的嵌套

# 课程表:字典 + 列表的嵌套
schedule = {
    "星期一": ["语文", "数学", "英语"],
    "星期二": ["数学", "科学", "体育"],
    "星期三": ["语文", "美术", "音乐"]
}

# 访问星期二第二节课
print(schedule["星期二"][1])  # 输出: 科学

复杂的嵌套结构

# 更复杂的课程表:多层嵌套
courses = {
    "MON": {
        "morning": ["数学", "英语", "绘画"],
        "afternoon": ["音乐", "体育"]
    },
    "TUE": {
        "morning": ["科学", "数学", "体育"],
        "afternoon": ["英语"]
    }
}

# 访问星期一上午第二节课
print(courses["MON"]["morning"][1])  # 输出: 英语

# 查看星期一下午课程的类型
print(type(courses["MON"]["afternoon"]))  # 输出: <class 'list'>

# 查看星期一上午第二节课的类型
print(type(courses["MON"]["morning"][1]))  # 输出: <class 'str'>

给家长的小贴士:嵌套结构理解起来比较困难,建议用“俄罗斯套娃“或“多层盒子“的类比。访问嵌套数据就像一层层打开盒子,每次只打开一层。


字典的排序

按键排序

scores = {"语文": 95, "数学": 98, "英语": 88}

# 按键排序
sorted_keys = sorted(scores.keys())
print(sorted_keys)  # 输出: ['数学', '英语', '语文']

# 按排序后的顺序遍历
for subject in sorted_keys:
    print(f"{subject}: {scores[subject]}")

# 输出:
# 数学: 98
# 英语: 88
# 语文: 95

按值排序

scores = {"语文": 95, "数学": 98, "英语": 88}

# 按值排序(从低到高)
sorted_items = sorted(scores.items(), key=lambda x: x[1])
print(sorted_items)  # 输出: [('英语', 88), ('语文', 95), ('数学', 98)]

# 按值排序(从高到低)
sorted_items = sorted(scores.items(), key=lambda x: x[1], reverse=True)
print(sorted_items)  # 输出: [('数学', 98), ('语文', 95), ('英语', 88)]

给家长的小贴士:lambda表达式对孩子来说比较抽象,可以简单地解释为“告诉Python按什么排序“。对于初学者,可以先跳过这个部分。


字典的应用案例

案例1:数学函数计算器 🧮

我们可以用字典来存储数学函数的值:

# 创建一个简单的函数表
function_table = {
    1: 2,    # f(1) = 2
    2: 4,    # f(2) = 4
    3: 6,    # f(3) = 6
    4: 8,    # f(4) = 8
    5: 10    # f(5) = 10
}

# 查询函数值
x = int(input("请输入x的值(1-5): "))
if x in function_table:
    y = function_table[x]
    print(f"f({x}) = {y}")
else:
    print("这个值不在表中")

# 你能猜出这是什么函数吗?
# 答案:f(x) = 2x (乘法函数)

数学挑战:发现规律 📊

# 更复杂的函数表
math_functions = {
    "正方形面积": {1: 1, 2: 4, 3: 9, 4: 16, 5: 25},
    "正方形周长": {1: 4, 2: 8, 3: 12, 4: 16, 5: 20},
    "圆的面积": {1: 3.14, 2: 12.56, 3: 28.26, 4: 50.24, 5: 78.5}
}

# 让用户选择函数
for name in math_functions:
    print(f"- {name}")

choice = input("\n请选择一个函数: ")
if choice in math_functions:
    print(f"\n{choice}的值:")
    for x, y in math_functions[choice].items():
        print(f"  当边长/半径 = {x} 时,结果 = {y}")

    # 让用户猜规律
    print("\n你能发现这些数字的规律吗?")

给家长的小贴士 🧑‍🏫

数学融入

  1. 函数关系

    • 引导孩子观察输入和输出的关系
    • 问:“当x增加1时,y增加多少?”
    • 这就是学习“变化率“的早期概念
  2. 找规律

    • 正方形面积:1, 4, 9, 16, 25 → 这些是什么数的平方?
    • 正方形周长:4, 8, 12, 16, 20 → 每次增加4
    • 引导孩子发现:面积 = 边长²,周长 = 边长 × 4
  3. 扩展练习

    • 让孩子自己创建一个函数表
    • 比如:f(x) = x + 3,f(x) = x × 2 + 1
    • 用字典存储前10个值

案例2:制作简单的翻译器

# 英汉词典
dictionary = {
    "hello": "你好",
    "world": "世界",
    "python": "蟒蛇",
    "computer": "电脑"
}

# 翻译功能
word = input("请输入要翻译的英文单词: ")
translation = dictionary.get(word.lower(), "词典里没有这个单词")

print(f"翻译结果: {translation}")

案例2:统计字符出现次数

# 统计字符串中每个字符出现的次数
text = "hello world"

# 创建空字典
char_count = {}

# 遍历字符串
for char in text:
    if char in char_count:
        char_count[char] += 1
    else:
        char_count[char] = 1

print(char_count)
# 输出: {'h': 1, 'e': 1, 'l': 3, 'o': 2, ' ': 1, 'w': 1, 'r': 1, 'd': 1}

案例3:制作简单的投票系统

# 投票系统
votes = {}

while True:
    name = input("请输入要投票的同学的名字(输入'结束'退出): ")

    if name == "结束":
        break

    # 使用get()方法,如果不存在则从0开始计数
    votes[name] = votes.get(name, 0) + 1
    print(f"{name}的票数: {votes[name]}")

# 输出最终结果
print("\n投票结果:")
for name, count in votes.items():
    print(f"{name}: {count}票")

案例4:学生成绩管理系统

# 学生成绩管理系统
students = {}

while True:
    print("\n===== 成绩管理系统 =====")
    print("1. 添加学生")
    print("2. 查询学生")
    print("3. 显示所有学生")
    print("4. 退出")

    choice = input("请选择操作 (1-4): ")

    if choice == "1":
        # 添加学生
        name = input("请输入学生姓名: ")
        score = int(input("请输入学生成绩: "))
        students[name] = score
        print(f"已添加: {name}, 成绩: {score}")

    elif choice == "2":
        # 查询学生
        name = input("请输入要查询的学生姓名: ")
        if name in students:
            print(f"{name}的成绩是: {students[name]}")
        else:
            print("没有找到该学生")

    elif choice == "3":
        # 显示所有学生
        if students:
            print("\n所有学生成绩:")
            for name, score in students.items():
                print(f"{name}: {score}分")
        else:
            print("还没有添加学生")

    elif choice == "4":
        print("再见!")
        break

    else:
        print("无效的选择,请重新输入")

给家长的小贴士:这些案例都是很好的综合练习,可以让孩子自己尝试实现,然后再和示例代码对比,找出差异。


实践练习

练习1:单位换算器 📏

创建一个单位换算程序,支持长度、重量、温度等单位的换算。

数学知识

  • 1米 = 100厘米
  • 1千克 = 1000克
  • 摄氏度转华氏度:F = C × 9/5 + 32
查看答案
# 单位换算器
conversions = {
    "长度": {"米": 1, "厘米": 0.01, "毫米": 0.001},
    "重量": {"千克": 1, "克": 0.001, "吨": 1000},
    "温度": {"摄氏度": "C", "华氏度": "F"}
}

print("=== 单位换算器 ===")
print("1. 长度换算")
print("2. 重量换算")
print("3. 温度换算")

choice = input("请选择换算类型 (1-3): ")

if choice == "1":
    # 长度换算
    value = float(input("请输入数值: "))
    unit = input("请输入单位 (米/厘米/毫米): ")
    target = input("请输入目标单位 (米/厘米/毫米): ")

    if unit in conversions["长度"] and target in conversions["长度"]:
        # 先转为米,再转为目标单位
        in_meters = value * conversions["长度"][unit]
        result = in_meters / conversions["长度"][target]
        print(f"{value}{unit} = {result}{target}")

elif choice == "2":
    # 重量换算(类似逻辑)
    value = float(input("请输入数值: "))
    unit = input("请输入单位 (千克/克/吨): ")
    target = input("请输入目标单位 (千克/克/吨): ")

    if unit in conversions["重量"] and target in conversions["重量"]:
        in_kg = value * conversions["重量"][unit]
        result = in_kg / conversions["重量"][target]
        print(f"{value}{unit} = {result}{target}")

elif choice == "3":
    # 温度换算
    value = float(input("请输入温度值: "))
    unit = input("请输入单位 (摄氏度/华氏度): ")

    if unit == "摄氏度":
        # C to F: F = C × 9/5 + 32
        result = value * 9/5 + 32
        print(f"{value}°C = {result:.1f}°F")
    elif unit == "华氏度":
        # F to C: C = (F - 32) × 5/9
        result = (value - 32) * 5/9
        print(f"{value}°F = {result:.1f}°C")

数学思考

  • 为什么要用字典存储单位换算率?(键值对的对应关系)
  • 温度换算为什么不能用简单的乘法?(引导理解线性函数 y = ax + b)

练习2:罗马数字转换器 ➗⚖️

罗马数字是古罗马人使用的数字系统,比如:I=1, V=5, X=10, L=50, C=100。

创建一个程序,在罗马数字和阿拉伯数字之间转换。

查看答案
# 罗马数字转换器
roman_to_arabic = {
    "I": 1,
    "V": 5,
    "X": 10,
    "L": 50,
    "C": 100,
    "D": 500,
    "M": 1000
}

print("=== 罗马数字转换器 ===")
print("1. 罗马数字 → 阿拉伯数字")
print("2. 阿拉伯数字 → 罗马数字")

choice = input("请选择 (1-2): ")

if choice == "1":
    # 罗马数字转阿拉伯数字
    roman = input("请输入罗马数字 (大写,如 XIV): ")
    total = 0
    prev_value = 0

    # 从右到左遍历
    for char in reversed(roman):
        value = roman_to_arabic[char]
        if value < prev_value:
            total -= value
        else:
            total += value
        prev_value = value

    print(f"{roman} = {total}")

elif choice == "2":
    # 简化版:阿拉伯数字转罗马数字(仅限1-10)
    arabic_to_roman = {
        1: "I", 2: "II", 3: "III", 4: "IV", 5: "V",
        6: "VI", 7: "VII", 8: "VIII", 9: "IX", 10: "X"
    }

    num = int(input("请输入数字 (1-10): "))
    if num in arabic_to_roman:
        print(f"{num} = {arabic_to_roman[num]}")
    else:
        print("这个版本只支持1-10的转换")

历史和数学

  • 罗马数字为什么后来被阿拉伯数字取代?(计算方便)
  • 罗马数字的“减法原则“:IV = 5-1 = 4,这体现了什么数学思想?

练习3:简单的电话簿

创建一个电话簿程序,支持以下功能:

  1. 添加联系人(姓名和电话)
  2. 查询联系人
  3. 显示所有联系人
  4. 删除联系人
查看答案
# 电话簿程序
phone_book = {}

while True:
    print("\n===== 电话簿 =====")
    print("1. 添加联系人")
    print("2. 查询联系人")
    print("3. 显示所有联系人")
    print("4. 删除联系人")
    print("5. 退出")

    choice = input("请选择操作 (1-5): ")

    if choice == "1":
        # 添加联系人
        name = input("请输入姓名: ")
        phone = input("请输入电话: ")
        phone_book[name] = phone
        print(f"已添加: {name}")

    elif choice == "2":
        # 查询联系人
        name = input("请输入要查询的姓名: ")
        if name in phone_book:
            print(f"{name}的电话: {phone_book[name]}")
        else:
            print("没有找到该联系人")

    elif choice == "3":
        # 显示所有联系人
        if phone_book:
            print("\n所有联系人:")
            for name, phone in phone_book.items():
                print(f"{name}: {phone}")
        else:
            print("电话簿是空的")

    elif choice == "4":
        # 删除联系人
        name = input("请输入要删除的联系人姓名: ")
        if name in phone_book:
            del phone_book[name]
            print(f"已删除: {name}")
        else:
            print("没有找到该联系人")

    elif choice == "5":
        print("再见!")
        break

    else:
        print("无效的选择,请重新输入")

练习2:单词统计器

编写一个程序,统计一段文本中每个单词出现的次数。

查看答案
# 单词统计器
text = input("请输入一段文本: ")

# 分割成单词
words = text.split()

# 统计词频
word_count = {}
for word in words:
    word_count[word] = word_count.get(word, 0) + 1

# 输出结果
print("\n单词出现次数:")
for word, count in sorted(word_count.items()):
    print(f"{word}: {count}次")

练习3:制作课程表

创建一个程序,管理一周的课程表。

查看答案
# 课程表管理
schedule = {}

weekdays = ["星期一", "星期二", "星期三", "星期四", "星期五"]

# 初始化课程表
for day in weekdays:
    schedule[day] = []

while True:
    print("\n===== 课程表管理 =====")
    print("1. 添加课程")
    print("2. 查看课程表")
    print("3. 退出")

    choice = input("请选择操作 (1-3): ")

    if choice == "1":
        # 添加课程
        for i, day in enumerate(weekdays):
            print(f"{i+1}. {day}")

        day_choice = int(input("请选择星期几 (1-5): ")) - 1
        course = input("请输入课程名称: ")
        schedule[weekdays[day_choice]].append(course)
        print(f"已添加: {weekdays[day_choice]} - {course}")

    elif choice == "2":
        # 查看课程表
        print("\n=== 本周课程表 ===")
        for day in weekdays:
            courses = schedule[day]
            if courses:
                courses_str = "、".join(courses)
                print(f"{day}: {courses_str}")
            else:
                print(f"{day}: 无课程")

    elif choice == "3":
        print("再见!")
        break

    else:
        print("无效的选择,请重新输入")

练习4:计算平均成绩

创建一个程序,管理多个学生的成绩,并计算平均分。

查看答案
# 成绩管理系统
students = {}

while True:
    print("\n===== 成绩管理 =====")
    print("1. 添加学生成绩")
    print("2. 查看学生成绩")
    print("3. 查看班级平均分")
    print("4. 退出")

    choice = input("请选择操作 (1-4): ")

    if choice == "1":
        # 添加学生
        name = input("请输入学生姓名: ")
        score = float(input("请输入成绩: "))
        students[name] = score
        print(f"已添加: {name}")

    elif choice == "2":
        # 查看成绩
        if students:
            print("\n所有学生成绩:")
            for name, score in students.items():
                print(f"{name}: {score}分")
        else:
            print("还没有添加学生")

    elif choice == "3":
        # 计算平均分
        if students:
            average = sum(students.values()) / len(students)
            print(f"班级平均分: {average:.2f}")
        else:
            print("还没有添加学生")

    elif choice == "4":
        print("再见!")
        break

    else:
        print("无效的选择,请重新输入")

练习5:简单的加密解密程序

创建一个简单的凯撒密码加密解密程序。

查看答案
# 凯撒密码加密解密
def create_cipher(shift):
    """创建密码本"""
    cipher = {}
    for i in range(26):
        original = chr(ord('a') + i)
        encrypted = chr(ord('a') + (i + shift) % 26)
        cipher[original] = encrypted
        cipher[original.upper()] = encrypted.upper()
    return cipher

def encrypt(text, cipher):
    """加密"""
    result = []
    for char in text:
        if char in cipher:
            result.append(cipher[char])
        else:
            result.append(char)
    return ''.join(result)

def decrypt(text, cipher):
    """解密"""
    # 创建反向密码本
    reverse_cipher = {v: k for k, v in cipher.items()}
    return encrypt(text, reverse_cipher)

# 主程序
shift = int(input("请输入偏移量 (1-25): "))
cipher = create_cipher(shift)

while True:
    print("\n===== 加密解密系统 =====")
    print("1. 加密")
    print("2. 解密")
    print("3. 退出")

    choice = input("请选择操作 (1-3): ")

    if choice == "1":
        text = input("请输入要加密的文本: ")
        encrypted = encrypt(text, cipher)
        print(f"加密结果: {encrypted}")

    elif choice == "2":
        text = input("请输入要解密的文本: ")
        decrypted = decrypt(text, cipher)
        print(f"解密结果: {decrypted}")

    elif choice == "3":
        print("再见!")
        break

    else:
        print("无效的选择,请重新输入")

练习6:数学成绩分析 📊

创建一个程序,分析班级数学成绩,计算最高分、最低分、平均分,并统计各分数段的人数。

查看答案
# 数学成绩分析
students = {
    "小明": 95,
    "小红": 87,
    "小华": 92,
    "小刚": 78,
    "小李": 88,
    "小张": 65,
    "小王": 90,
    "小陈": 82,
    "小刘": 76,
    "小赵": 94
}

# 计算统计数据
scores = list(students.values())
max_score = max(scores)
min_score = min(scores)
avg_score = sum(scores) / len(scores)

print(f"=== 数学成绩分析 ===")
print(f"最高分: {max_score}")
print(f"最低分: {min_score}")
print(f"平均分: {avg_score:.2f}")

# 按分数段统计
grade_ranges = {
    "优秀(90-100)": 0,
    "良好(80-89)": 0,
    "及格(60-79)": 0,
    "不及格(0-59)": 0
}

for score in scores:
    if score >= 90:
        grade_ranges["优秀(90-100)"] += 1
    elif score >= 80:
        grade_ranges["良好(80-89)"] += 1
    elif score >= 60:
        grade_ranges["及格(60-79)"] += 1
    else:
        grade_ranges["不及格(0-59)"] += 1

print("\n分数段统计:")
for range_name, count in grade_ranges.items():
    print(f"{range_name}: {count}人")

# 找出成绩最高和最低的学生
max_student = max(students, key=students.get)
min_student = min(students, key=students.get)

print(f"\n最高分学生: {max_student} ({students[max_student]}分)")
print(f"最低分学生: {min_student} ({students[min_student]}分)")

数学知识点

  • 平均数:所有分数的和 ÷ 人数
  • 中位数:如果按分数排序,中间位置的分数
  • 众数:出现次数最多的分数
  • 极差:最高分 - 最低分

扩展挑战

  • 计算方差(衡量分数的分散程度)
  • 画出分数分布的柱状图
  • 比较不同班级的成绩

综合应用:人员信息管理系统

结合前面学的知识,我们创建一个完整的人员信息管理系统:

# 人员信息管理系统
people = {}

def add_person():
    """添加人员"""
    name = input("请输入姓名: ")
    age = input("请输入年龄: ")
    phone = input("请输入电话: ")

    people[name] = {
        "age": age,
        "phone": phone
    }
    print(f"已添加: {name}")

def find_person():
    """查找人员"""
    name = input("请输入要查找的姓名: ")
    if name in people:
        info = people[name]
        print(f"姓名: {name}")
        print(f"年龄: {info['age']}")
        print(f"电话: {info['phone']}")
    else:
        print("没有找到该人员")

def list_all():
    """列出所有人员"""
    if people:
        print("\n所有人员信息:")
        print("-" * 40)
        for name, info in people.items():
            print(f"姓名: {name}")
            print(f"年龄: {info['age']}")
            print(f"电话: {info['phone']}")
            print("-" * 40)
    else:
        print("还没有添加人员")

def delete_person():
    """删除人员"""
    name = input("请输入要删除的人员姓名: ")
    if name in people:
        del people[name]
        print(f"已删除: {name}")
    else:
        print("没有找到该人员")

# 主菜单
while True:
    print("\n===== 人员信息管理系统 =====")
    print("1. 添加人员")
    print("2. 查找人员")
    print("3. 列出所有人员")
    print("4. 删除人员")
    print("5. 退出")

    choice = input("请选择操作 (1-5): ")

    if choice == "1":
        add_person()
    elif choice == "2":
        find_person()
    elif choice == "3":
        list_all()
    elif choice == "4":
        delete_person()
    elif choice == "5":
        print("再见!")
        break
    else:
        print("无效的选择,请重新输入")

给家长的小贴士:这个综合项目使用了字典的嵌套、增删改查等所有核心概念,是很好的实战练习。


字典和列表的选择

什么时候使用列表?

  • 需要按顺序存储数据
  • 使用数字索引访问元素
  • 数据之间没有明确的“键“关系
  • 例如:购物清单、待办事项列表

什么时候使用字典?

  • 需要用有意义的名称访问数据
  • 数据有明确的“键-值“关系
  • 需要快速查找和更新
  • 例如:电话簿、成绩表、配置信息

对比示例

# 使用列表存储学生信息(不推荐)
student_list = ["小明", 12, 6, 95]  # 难以记住每个位置的含义

# 使用字典存储学生信息(推荐)
student_dict = {
    "name": "小明",
    "age": 12,
    "grade": 6,
    "score": 95
}  # 每个字段都有明确的含义

给家长的小贴士:选择合适的数据结构是编程的重要能力,鼓励孩子在编写程序前先思考:“用列表还是字典更合适?”


常见错误和调试

错误1:使用不存在的键

scores = {"语文": 95, "数学": 98}

# 错误:直接访问不存在的键
print(scores["英语"])  # KeyError: '英语'

# 正确:使用get()方法
print(scores.get("英语", "没有这门课"))

错误2:使用可变类型作为键

# 错误:列表不能作为键
# my_dict = {[1, 2]: "value"}  # TypeError

# 正确:元组可以作为键
my_dict = {(1, 2): "value"}

错误3:遍历字典时修改字典

scores = {"语文": 95, "数学": 98, "英语": 88}

# 错误:遍历时修改字典
for subject in scores:
    if scores[subject] < 90:
        del scores[subject]  # RuntimeError

# 正确:先收集要删除的键,再删除
to_remove = [subject for subject in scores if scores[subject] < 90]
for subject in to_remove:
    del scores[subject]

错误4:混淆赋值和copy()

original = {"语文": 95, "数学": 98}

# 错误:这只是创建了一个引用
copied = original
copied["英语"] = 88
print(original)  # original也被修改了!

# 正确:使用copy()创建独立副本
copied = original.copy()
copied["英语"] = 88
print(original)  # original不受影响

调试技巧

  1. 打印字典内容
scores = {"语文": 95, "数学": 98}
print(scores)  # 查看完整字典
  1. 检查键是否存在
if "数学" in scores:
    print("数学成绩存在")
  1. 使用type()检查类型
print(type(scores))  # 确认是字典类型

给家长的小贴士:字典的错误通常比较隐蔽,建议在调试时多使用print()语句,逐步检查每一步的执行结果。


性能考虑

字典的查找速度

字典的查找速度非常快(O(1)),而列表的查找速度较慢(O(n))。

# 使用列表查找(慢)
students_list = ["小明", "小红", "小华", "小刚", "小李"]
if "小华" in students_list:  # 需要逐个比较
    print("找到了")

# 使用字典查找(快)
students_dict = {"小明": 1, "小红": 2, "小华": 3}
if "小华" in students_dict:  # 直接找到
    print("找到了")

什么时候考虑性能?

  • 数据量很大时(比如超过1000个元素)
  • 需要频繁查找时
  • 对性能要求高的程序

给家长的小贴士:对于小学阶段的学习,性能不是重点,但了解这个知识点有助于培养良好的编程习惯。


字典的高级应用

使用字典作为缓存

# 斐波那契数列(带缓存)
cache = {}

def fib(n):
    if n in cache:
        return cache[n]

    if n <= 1:
        result = n
    else:
        result = fib(n-1) + fib(n-2)

    cache[n] = result
    return result

print(fib(100))  # 计算很快,因为有缓存

使用字典统计

# 统计单词词频
text = "hello world hello python world"

words = text.split()
word_count = {}

for word in words:
    word_count[word] = word_count.get(word, 0) + 1

print(word_count)
# 输出: {'hello': 2, 'world': 2, 'python': 1}

使用字典分组

# 按成绩分组
students = [
    {"name": "小明", "score": 95},
    {"name": "小红", "score": 87},
    {"name": "小华", "score": 92}
]

# 按分数段分组
groups = {"优秀": [], "良好": [], "及格": []}

for student in students:
    score = student["score"]
    if score >= 90:
        groups["优秀"].append(student["name"])
    elif score >= 80:
        groups["良好"].append(student["name"])
    else:
        groups["及格"].append(student["name"])

print(groups)

给家长的小贴士:这些高级应用可能比较复杂,可以让孩子先掌握基础,等有更多编程经验后再学习。


字典 vs 其他数据结构

数据结构特点适用场景
列表有序、可重复存储序列数据
元组有序、不可变固定不变的数据
集合无序、唯一去重、集合运算
字典键值对快速查找、关联数据
# 列表:购物清单
shopping_list = ["苹果", "香蕉", "橙子"]

# 元组:固定坐标
point = (10, 20)

# 集合:去重
numbers = {1, 2, 3, 2, 1}  # {1, 2, 3}

# 字典:成绩表
scores = {"小明": 95, "小红": 98}

给家长的小贴士:让孩子理解不同数据结构的特点和适用场景,有助于选择合适的工具。


章节小结

核心知识点

  1. 字典的基本概念

    • 字典是键值对的集合
    • 键必须是不可变类型且唯一
    • 值可以是任意类型
  2. 字典与数学的关联 📊:

    • 字典就像数学中的“映射“关系
    • 键(key)相当于自变量 x
    • 值(value)相当于因变量 y
    • 字典表达了“一对一“的对应关系
  3. 字典为什么这么快? ⚡:

    • 使用了哈希表技术
    • 哈希函数把键转换成数字(类似取余数)
    • 可以直接定位到存储位置,不需要一个个找
    • 列表查找:O(n),字典查找:O(1)
  4. 字典的基本操作

    • 创建:{}dict()
    • 访问:dict[key]dict.get(key)
    • 添加:dict[key] = value
    • 修改:dict[key] = new_value
    • 删除:del dict[key]dict.pop(key)
  5. 字典的常用方法

    • keys(): 获取所有键
    • values(): 获取所有值
    • items(): 获取所有键值对
    • get(): 安全访问
    • update(): 更新字典
    • clear(): 清空字典
  6. 遍历字典

    • 遍历键:for key in dict
    • 遍历值:for value in dict.values()
    • 遍历键值对:for key, value in dict.items()
  7. 嵌套字典

    • 字典的值可以是另一个字典
    • 访问嵌套数据:dict[key1][key2]

重要概念

  • 字典的键必须是不可变类型(字符串、数字、元组)
  • 字典的键必须唯一(就像数学函数中每个x只能对应一个y)
  • 字典的查找速度很快(O(1)),因为使用了哈希表
  • 字典适合存储有关联关系的数据

数学知识回顾 📐

通过本章,你复习了以下数学知识:

  1. 映射和函数

    • 理解“输入→输出“的对应关系
    • 一一对应的概念
  2. 统计数据分析

    • 平均数、最大值、最小值
    • 数据分组统计
  3. 单位换算

    • 长度、重量、温度换算
    • 理解比例关系
  4. 找规律

    • 观察数列的变化趋势
    • 发现函数关系式

计算机知识 💻

通过本章,你了解了以下计算机知识:

  1. 哈希表

    • 什么是哈希函数
    • 为什么字典查找速度快
    • 时间复杂度:O(1) vs O(n)
  2. 数据结构选择

    • 什么时候用列表
    • 什么时候用字典
    • 权衡速度和内存

挑战练习

挑战1:制作一个简单的游戏配置系统

创建一个游戏配置系统,可以设置和读取游戏参数(如难度、音量、玩家名称等)。

提示

使用字典存储配置信息,每个配置项是一个键值对。

挑战2:制作一个图书管理系统

创建一个图书管理系统,每本书包含:书名、作者、出版社、出版年份、价格等信息。支持添加、查找、删除、列出所有书籍等功能。

提示

使用嵌套字典,书名作为键,书的详细信息作为值。

挑战3:制作一个简单的投票统计系统

创建一个投票统计系统,可以统计多个候选人的得票数,并按票数排序显示结果。

提示

使用字典存储候选人姓名和票数,使用sorted()函数排序。


下一步

恭喜你完成了字典的学习!现在你已经掌握了:

✅ 列表(List)- 按顺序存储数据 ✅ 字典(Dictionary)- 按键值对存储数据

这两种数据结构是Python中最常用的数据存储方式。你已经理解了:

  • 字典就像数学中的“映射“关系
  • 字典使用哈希表技术,查找速度非常快
  • 字典非常适合存储有关联关系的数据

本章与数学的联结 📊

通过字典,你其实已经在用编程的方式理解数学中的函数概念了!

在数学课上,你学过函数 y = f(x),这和字典的 “键→值” 是不是非常相似?

数学概念Python字典
自变量 x键(key)
因变量 y值(value)
函数 f(x)字典的映射
定义域所有的键
值域所有的值

下一章预告 🚀

下一章,我们将学习函数(Function)。

等等,函数不是数学里的概念吗?为什么编程里也有函数?

非常好的问题!编程中的函数和数学中的函数确实有很多相似之处:

  • 它们都接收“输入“(参数)
  • 它们都进行某种“处理“或“计算“
  • 它们都产生“输出“(返回值)

但编程中的函数更强大,它可以:

  • 让代码更简洁(不用重复写相同的代码)
  • 让代码更清晰(把复杂问题分解成小问题)
  • 让代码可重用(写一次,用多次)

你将学会:

  • 如何定义自己的函数
  • 函数的参数和返回值(就像数学函数的自变量和因变量)
  • 如何用函数解决实际问题

继续加油,你正在成为一名优秀的程序员!🎉