python 字典 列表 类比c++【python】
文章目录
- python 字典 列表 类比c++
- 字典
- 一、核心联系(底层与功能共性)
- 二、主要区别(特性与使用差异)
- 三、代码示例对比(直观感受差异)
- Python 字典
- C++ `std::unordered_map`
- 四、总结
- 列表
- # 使用 `list()` 创建列表
- 一、相似之处(基础功能)
- 二、核心差异(列表更灵活)
- 三、总结
python 字典 列表 类比c++
字典
- 直接使用花括号
{}
初始化(最常用)
通过 {键1: 值1, 键2: 值2, ...}
直接定义键值对,键和值之间用冒号 :
分隔,键值对之间用逗号 ,
分隔。
# 基础键值对(键可以是字符串、数字等可哈希类型)
dict1 = {"name": "cxq", "age": 22, "is_student": True}# 空字典
dict2 = {}# 嵌套字典(值可以是字典)
dict3 = {"student": {"name": "cxq", "age": 22},"scores": {"math": 100, "chinese": 80}
}print(dict1) # {'name': 'cxq', 'age': 22, 'is_student': True}
print(dict2) # {}
print(dict3) # {'student': {'name': 'cxq', 'age': 22}, 'scores': {'math': 100, 'chinese': 80}}
- 使用字典推导式(动态生成字典)
通过 {键表达式: 值表达式 for 变量 in 可迭代对象}
语法快速生成字典,适合根据已有数据动态生成键值对。
# 生成键为1-5、值为键平方的字典
dict4 = {x: x**2 for x in range(1, 6)}# 筛选键为偶数的字典(带条件)
dict5 = {x: x*2 for x in range(1, 11) if x % 2 == 0}# 从列表生成(键值对应)
keys = ["a", "b", "c"]
values = [1, 2, 3]
dict6 = {k: v for k, v in zip(keys, values)} # 结合zip()函数print(dict4) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
print(dict5) # {2: 4, 4: 8, 6: 12, 8: 16, 10: 20}
print(dict6) # {'a': 1, 'b': 2, 'c': 3}
- 使用
dict()
内置函数(转换或初始化)
dict()
函数可通过多种参数形式创建字典,灵活度高,常见用法如下:
(1)通过 “关键字参数” 创建(键为字符串时简化写法)
# 关键字参数形式(键名自动转为字符串)
dict7 = dict(name="cxq", age=22, gender="男")
print(dict7) # {'name': 'cxq', 'age': 22, 'gender': '男'}
(2)通过 “可迭代对象” 创建(如列表 / 元组的键值对序列)
可迭代对象需包含 “键值对” 元素(如 (键, 值)
元组、[键, 值]
列表)。
# 列表中的元组(每个元组是一个键值对)
dict8 = dict([("name", "cxq"), ("age", 22), ("scores", [80, 100])])# 元组中的列表
dict9 = dict((["a", 1], ["b", 2]))print(dict8) # {'name': 'cxq', 'age': 22, 'scores': [80, 100]}
print(dict9) # {'a': 1, 'b': 2}
例如
# 1. 创建字典dic1:使用dict()函数,参数为包含键值对的列表(列表元素是元组,每个元组表示一个键值对)
# - 'math_scores':对应值为列表[80, 100](表示数学成绩,假设是两次考试的分数)
dic1 = dict([('name', 'zhangsan'), ('age', 20), ('math_scores', [80, 100])])# - 先通过键'math_scores'访问dic1中存储的成绩列表(即[80, 100])
# - 再通过列表索引0获取列表中的第一个元素
zhangsan_math1 = dic1['math_scores'][0]# 3. 打印张三的第一次数学成绩
print("zhangsan_math1 :", zhangsan_math1) # 输出:zhangsan_math1 : 80# 4. 创建字典dic2:使用dict()函数,参数为包含键值对的元组(元组元素是列表,每个列表表示一个键值对)
# - 'chinese_scores':对应值为列表[90, 100](表示语文成绩,假设是两次考试的分数)
# 注意:dict()函数接受任意"包含键值对的可迭代对象",这里元组中的列表与dic1中列表中的元组效果一致
dic2 = dict((['name', 'lisi'], ['age', 21], ['chinese_scores', [90, 100]]))# - 先通过键'chinese_scores'访问dic2中存储的成绩列表(即[90, 100])
# - 再通过列表索引0获取列表中的第一个元素
lisi_chinese1 = dic2['chinese_scores'][0]# 6. 打印李四的第一次语文成绩
print("lisi_chinese1 :", lisi_chinese1) # 输出:lisi_chinese1 : 90
student = {'name': "cxq",'age': 22,'grades': {'chinese': 80, 'math': 100}
}
print("student :", student)
print("student grades:", student['grades']["chinese"])
一、核心联系(底层与功能共性)
- 底层数据结构相同两者均基于哈希表(Hash Table) 实现,通过键(Key)的哈希值快速定位存储位置,因此平均时间复杂度均为:
- 插入(
dict[key] = value
/unordered_map.insert(...)
):O(1) - 查找(
dict[key]
/unordered_map.find(...)
):O(1) - 删除(
del dict[key]
/unordered_map.erase(...)
):O(1)
- 插入(
- 核心功能一致都是键值对(Key-Value)关联容器,核心作用是通过 “键” 快速映射到 “值”,支持:
- 唯一键(重复插入相同键会覆盖旧值);
- 动态增删键值对;
- 通过键直接访问值。
- 键的基本要求相同两者都要求键必须是 “可哈希的”(即键的哈希值在生命周期内不可变,且支持相等性比较):
- Python 中,键必须是不可变类型(如
int
、str
、tuple
等,因为可变类型如list
不可哈希); - C++ 中,键类型需支持哈希函数(
std::hash<Key>
)和相等运算符(operator==
),自定义类型需手动实现这两者。
- Python 中,键必须是不可变类型(如
二、主要区别(特性与使用差异)
特性 | Python 字典(dict ) | C++ std::unordered_map |
---|---|---|
有序性 | Python 3.7+ 保证插入顺序(遍历顺序与插入顺序一致) | 完全无序(遍历顺序与插入顺序无关,由哈希值决定) |
内存管理 | 全自动(Python 解释器负责分配 / 释放内存,无需手动干预) | 需手动管理(如容器销毁时释放内存,动态扩容由内部处理,但需注意迭代器失效问题) |
内置功能丰富度 | 提供大量便捷方法:- get(key, default) :找不到键时返回默认值- items() /keys() /values() :返回动态视图(反映实时修改)- 字典推导式:快速生成字典- pop(key, default) :删除并返回值 | 功能较基础,需通过成员函数操作:- 查找需用 find(key) (返回迭代器)- 无内置 “默认值” 方法,需手动判断 find 结果- 迭代需通过迭代器(begin() /end() ) |
哈希冲突处理 | 采用开放寻址法(当哈希冲突时,通过探测下一个空闲位置解决) | 采用链地址法(拉链法)(哈希冲突时,在同一位置用链表存储冲突元素) |
迭代器与视图 | items() /keys() /values() 返回 “视图对象”(动态关联字典,修改字典会同步反映到视图) | 迭代器是 “快照” 式的,修改容器(如插入 / 删除元素)可能导致迭代器失效(需重新获取) |
键值类型灵活性 | 键和值可以是任意类型(键需可哈希,值无限制,如 {1: "a", "b": [1,2]} ) | 键和值的类型需在声明时固定(模板参数决定,如 unordered_map<int, string> 只能存 int 键和 string 值) |
三、代码示例对比(直观感受差异)
Python 字典
# 初始化字典(支持混合类型键值)
student = {"name": "cxq", 22: "age", "grades": {"math": 100}}# 查找(不存在时返回默认值,无需手动判断)
print(student.get("name", "未知")) # 输出:cxq
print(student.get("gender", "未知")) # 输出:未知(安全处理)# 插入/修改(动态扩容,无需关心容量)
student["gender"] = "男" # 插入新键值对
student[22] = 23 # 修改已有键的值# 遍历(按插入顺序,直接获取键值对)
for key, value in student.items():print(f"{key}: {value}")
# 输出顺序与插入顺序一致:name → 22 → grades → gender
C++ std::unordered_map
#include <unordered_map>
#include <iostream>
#include <string>
using namespace std;int main() {// 声明时固定键值类型(键:string,值:string)unordered_map<string, string> student = {{"name", "cxq"}, {"age", "22"}};// 查找(需手动判断是否存在,无默认值方法)auto it = student.find("name");if (it != student.end()) { // 必须检查迭代器是否有效cout << it->second << endl; // 输出:cxq}// 插入/修改(需注意类型匹配)student["gender"] = "男"; // 插入student["age"] = "23"; // 修改// 遍历(无序,顺序由哈希值决定)for (const auto& pair : student) {cout << pair.first << ": " << pair.second << endl;}// 输出顺序不确定(可能与插入顺序完全不同)return 0;
}
四、总结
- 联系:两者均基于哈希表实现,核心功能是高效的键值对存储与访问,平均时间复杂度均为 O (1),且都要求键可哈希。
- 区别:Python 字典更注重易用性和动态特性(自动内存管理、插入有序、丰富的内置方法),而
std::unordered_map
更强调类型严格性和底层可控性(固定类型、手动内存管理、迭代器机制)。
如果熟悉 std::unordered_map
,可以快速理解 Python 字典的核心逻辑;反之,字典的便捷特性(如默认值、动态视图)则是 Python 对哈希表容器的 “人性化优化”
列表
# 使用 list()
创建列表
list()
可以将可迭代对象(如字符串、元组、range、集合等)转换为列表。
# 字符串转列表(每个字符作为元素)
str_to_list = list("python")
# 元组转列表
tuple_to_list = list((1, 2, 3))
# range对象转列表(生成连续整数)
range_to_list = list(range(5)) # range(5) 等价于 0-4
# 集合转列表(注意:集合无序,列表顺序可能不固定)
set_to_list = list({1, 2, 3})print(str_to_list) # ['p', 'y', 't', 'h', 'o', 'n']
print(tuple_to_list) # [1, 2, 3]
print(range_to_list) # [0, 1, 2, 3, 4]
print(set_to_list) # [1, 2, 3](顺序可能不同)
通过 split()
方法分割字符串生成列表
字符串的 split()
方法可以按指定分隔符分割字符串,返回一个列表(常用于处理文本数据)
# 按空格分割
str1 = "I love Python"
list7 = str1.split() # 不指定分隔符时,默认按任意空白字符(空格、换行等)分割
# 按逗号分割
str2 = "apple,banana,orange"
list8 = str2.split(",")print(list7) # ['I', 'love', 'Python']
print(list8) # ['apple', 'banana', 'orange']
# 1. 创建列表(可包含不同类型元素)
my_list = ["苹果", 25, True, 3.14, ["嵌套列表", "元素"]]
print("1. 初始列表:", my_list)# 2. 访问列表元素(通过索引,索引从0开始)
print("\n2. 访问元素:")
print("第一个元素(索引0):", my_list[0])
print("倒数第二个元素(负索引-2):", my_list[-2]) # 负索引从末尾开始计数
print("嵌套列表的第一个元素:", my_list[4][0]) # 访问嵌套列表# 3. 修改列表元素(列表是可变的,可直接通过索引修改)
my_list[1] = 30 # 将索引1的元素从25改为30
print("\n3. 修改后的列表:", my_list)# 4. 列表添加元素
print("\n4. 添加元素:")
# append:在末尾添加单个元素
my_list.append("新元素")
print("append后:", my_list)# insert:在指定索引位置插入元素
my_list.insert(2, "插入的元素") # 在索引2处之前插入
print("insert后:", my_list)# extend:合并另一个列表(添加多个元素)
my_list.extend(["a", "b"])
print("extend后:", my_list)# 5. 列表删除元素
print("\n5. 删除元素:")
# del:通过索引删除
del my_list[3] # 删除索引3的元素
print("del后:", my_list)print("\n5. 删除元素:")
# 先检查苹果是否在列表中,再删除
if '苹果' in my_list:my_list.remove('苹果')print("remove后:", my_list)
else:print("列表中没有苹果,无需删除")# 再执行其他删除操作
print("del后前:" ,my_list)
del my_list[3]
print("del后:", my_list)popped = my_list.pop()
print("pop删除的元素:", popped)
print("pop后:", my_list)# 6. 列表切片(获取子列表,语法:list[start:end:step],左闭右开)
print("\n6. 切片操作:")
numbers = [10, 20, 30, 40, 50, 60]
print("原数字列表:", numbers)
print("索引1到3(不包含3):", numbers[1:3]) # [20, 30]
print("从索引2到末尾:", numbers[2:]) # [30, 40, 50, 60]
print("从开头到索引4:", numbers[:4]) # [10, 20, 30, 40]
print("步长为2(间隔1个元素):", numbers[::2]) # [10, 30, 50]
print("反转列表(步长为-1):", numbers[::-1]) # [60, 50, 40, 30, 20, 10]# 7. 列表遍历
print("\n7. 遍历列表:")
fruits = ["香蕉", "橙子", "葡萄"]
for fruit in fruits: # 直接遍历元素print(f"水果: {fruit}")print(f"enumerate: " ,fruit)
for index, fruit in enumerate(fruits): # 同时获取索引和元素print(f"索引{index}: {fruit}")# 8. 列表常用方法
print("\n8. 常用方法:")
nums = [3, 1, 4, 1, 5, 9]
print("原数字列表:", nums)
print("元素个数(len):", len(nums)) # 长度
print("元素1出现的次数(count):", nums.count(1)) # 计数
nums.sort() # 排序(默认升序)
print("排序后:", nums)
nums.reverse() # 反转
print("反转后:", nums)# 9. 列表推导式(快速创建列表的简洁语法)
print("\n9. 列表推导式:")
# 创建1-10的平方列表
squares = [x**2 for x in range(1, 11)]
print("1-10的平方:", squares)# 筛选偶数
evens = [x for x in range(1, 20) if x % 2 == 0]
print("1-19的偶数:", evens)
Python 的列表(List)和 C 语言的数组(Array)在基础功能上有相似之处,但在底层实现、灵活性和功能上有很大差异。可以理解为:列表是 “增强版的动态数组”,但比 C 语言的数组更灵活。
一、相似之处(基础功能)
- 都是元素的有序集合两者都能按顺序存储多个元素,且都支持通过索引(下标) 访问单个元素(索引从 0 开始)。
- C 语言数组:
int arr[3] = {1,2,3};
→ 通过arr[0]
访问第一个元素。 - Python 列表:
lst = [1,2,3]
→ 通过lst[0]
访问第一个元素。
- C 语言数组:
- 都支持遍历元素都可以通过循环(如
for
循环)依次访问所有元素。
二、核心差异(列表更灵活)
特性 | C 语言数组 | Python 列表 |
---|---|---|
大小是否固定 | 固定大小:声明时必须指定长度,之后不能修改(如int arr[5] 只能存 5 个元素)。 | 动态大小:可随时添加 / 删除元素,长度自动变化(如lst.append(4) 直接扩容)。 |
元素类型 | 只能存储相同类型的元素(如int 数组只能存整数,char 数组只能存字符)。 | 可存储不同类型的元素(如[1, "a", True, 3.14] 混合整数、字符串、布尔值等)。 |
内存管理 | 需手动管理内存(如malloc 分配、free 释放),且元素在内存中连续存储。 | 内存由 Python 自动管理(无需手动分配 / 释放),元素在内存中不一定连续(底层是动态数组 + 指针)。 |
内置功能 | 无内置方法,需手动实现增删、排序等操作(如插入元素需移动其他元素)。 | 自带丰富的内置方法(append() 添加、remove() 删除、sort() 排序等),操作便捷。 |
多维结构 | 支持多维数组(如int arr[2][3] ),内存是连续的二维块。 | 支持嵌套列表(如[[1,2], [3,4]] ),本质是 “列表的列表”,内存不连续。 |
三、总结
- 相似点:都是 “有序存储多个元素的容器”,支持索引访问和遍历,这是两者最直观的共性。
- 差异点:Python 列表是动态、多类型、自带丰富功能的 “高级容器”,而 C 语言数组是固定大小、单类型、需手动管理的 “底层数据结构”。
简单说:列表可以看作是 C 语言数组的 “升级版”,牺牲了一点底层可控性,换来更灵活的使用体验(尤其适合快速开发)