4.6 数据结构的选择与应用¶
在Python编程中,选择合适的数据结构对于程序的效率和可读性至关重要。本节将对前面介绍的数据结构进行对比,并提供选择指南。
4.6.1 各种数据结构的特点对比¶
下面是Python主要数据结构的特点对比:
# 数据结构特点对比示例
import sys
# 创建各种数据结构并比较
test_str = "Python"
test_list = ["P", "y", "t", "h", "o", "n"]
test_tuple = ("P", "y", "t", "h", "o", "n")
test_dict = {"P": 1, "y": 2, "t": 3, "h": 4, "o": 5, "n": 6}
test_set = {"P", "y", "t", "h", "o", "n"}
# 比较内存占用
print("内存占用比较:")
print(f"字符串: {sys.getsizeof(test_str)} 字节")
print(f"列表: {sys.getsizeof(test_list)} 字节")
print(f"元组: {sys.getsizeof(test_tuple)} 字节")
print(f"字典: {sys.getsizeof(test_dict)} 字节")
print(f"集合: {sys.getsizeof(test_set)} 字节")
# 特性对比表格
print("\n数据结构特性对比:")
print("-" * 70)
print(f"{'特性':<15}{'字符串':<12}{'列表':<12}{'元组':<12}{'字典':<12}{'集合':<12}")
print("-" * 70)
print(f"{'可变性':<15}{'不可变':<12}{'可变':<12}{'不可变':<12}{'可变':<12}{'可变':<12}")
print(f"{'有序性':<15}{'有序':<12}{'有序':<12}{'有序':<12}{'有序*':<12}{'无序':<12}")
print(f"{'索引访问':<15}{'支持':<12}{'支持':<12}{'支持':<12}{'键访问':<12}{'不支持':<12}")
print(f"{'重复元素':<15}{'允许':<12}{'允许':<12}{'允许':<12}{'键唯一':<12}{'不允许':<12}")
print(f"{'异构元素':<15}{'字符':<12}{'任意类型':<12}{'任意类型':<12}{'键值对':<12}{'可哈希类型':<12}")
print("-" * 70)
print("* Python 3.7+中字典保持插入顺序")
输出结果:
内存占用比较:
字符串: 55 字节
列表: 120 字节
元组: 88 字节
字典: 232 字节
集合: 216 字节
数据结构特性对比:
----------------------------------------------------------------------
特性 字符串 列表 元组 字典 集合
----------------------------------------------------------------------
可变性 不可变 可变 不可变 可变 可变
有序性 有序 有序 有序 有序* 无序
索引访问 支持 支持 支持 键访问 不支持
重复元素 允许 允许 允许 键唯一 不允许
异构元素 字符 任意类型 任意类型 键值对 可哈希类型
----------------------------------------------------------------------
* Python 3.7+中字典保持插入顺序
4.6.2 不同场景下的数据结构选择¶
# 不同场景的数据结构选择示例
# 1. 需要有序数据时
print("有序数据场景:")
# 使用列表存储学生成绩并保持顺序
scores = [85, 92, 78, 90, 88]
print(f"原始成绩: {scores}")
scores.sort()
print(f"排序后成绩: {scores}")
# 使用元组存储不可变的坐标点
point = (10, 20)
print(f"坐标点: {point}")
# 2. 需要快速查找时
print("\n快速查找场景:")
# 使用字典存储学生信息,通过学号快速查找
students = {
"1001": {"name": "张三", "age": 20, "major": "计算机科学"},
"1002": {"name": "李四", "age": 21, "major": "数学"},
"1003": {"name": "王五", "age": 22, "major": "物理"}
}
print(f"查找学号1002的学生: {students['1002']['name']}")
# 使用集合进行快速成员检测
allowed_users = {"admin", "manager", "editor"}
user = "editor"
print(f"用户'{user}'是否有权限: {user in allowed_users}")
# 3. 需要唯一元素时
print("\n唯一元素场景:")
# 使用集合去除重复元素
visitor_ips = ["192.168.1.1", "192.168.1.2", "192.168.1.1",
"192.168.1.3", "192.168.1.2", "192.168.1.4"]
unique_ips = set(visitor_ips)
print(f"原始IP列表: {visitor_ips}")
print(f"唯一IP数量: {len(unique_ips)}")
print(f"唯一IP列表: {unique_ips}")
# 4. 需要键值对映射时
print("\n键值对映射场景:")
# 使用字典存储配置信息
config = {
"host": "localhost",
"port": 8080,
"debug": True,
"max_connections": 100
}
print(f"服务器配置: {config}")
print(f"服务器端口: {config['port']}")
# 使用字典计数
words = ["apple", "banana", "apple", "orange", "banana", "apple"]
word_count = {}
for word in words:
word_count[word] = word_count.get(word, 0) + 1
print(f"单词列表: {words}")
print(f"单词计数: {word_count}")
输出结果:
有序数据场景:
原始成绩: [85, 92, 78, 90, 88]
排序后成绩: [78, 85, 88, 90, 92]
坐标点: (10, 20)
快速查找场景:
查找学号1002的学生: 李四
用户'editor'是否有权限: True
唯一元素场景:
原始IP列表: ['192.168.1.1', '192.168.1.2', '192.168.1.1', '192.168.1.3', '192.168.1.2', '192.168.1.4']
唯一IP数量: 4
唯一IP列表: {'192.168.1.2', '192.168.1.3', '192.168.1.1', '192.168.1.4'}
键值对映射场景:
服务器配置: {'host': 'localhost', 'port': 8080, 'debug': True, 'max_connections': 100}
服务器端口: 8080
单词列表: ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
单词计数: {'apple': 3, 'banana': 2, 'orange': 1}
4.6.3 性能考量¶
在选择数据结构时,需要考虑操作的时间复杂度和空间复杂度。
# 性能考量示例
import time
import random
# 准备测试数据
small_list = list(range(1000))
random.shuffle(small_list)
small_set = set(small_list)
small_dict = {i: i for i in small_list}
# 测试查找性能
print("查找性能测试:")
# 列表查找
start = time.time()
for _ in range(1000):
500 in small_list
list_time = time.time() - start
print(f"列表查找耗时: {list_time:.6f}秒")
# 集合查找
start = time.time()
for _ in range(1000):
500 in small_set
set_time = time.time() - start
print(f"集合查找耗时: {set_time:.6f}秒")
# 字典查找
start = time.time()
for _ in range(1000):
500 in small_dict
dict_time = time.time() - start
print(f"字典查找耗时: {dict_time:.6f}秒")
print(f"集合比列表快: {list_time/set_time:.1f}倍")
print(f"字典比列表快: {list_time/dict_time:.1f}倍")
# 常见操作的时间复杂度
print("\n常见操作的时间复杂度:")
print("-" * 70)
print(f"{'操作':<20}{'列表':<15}{'元组':<15}{'字典':<15}{'集合':<15}")
print("-" * 70)
print(f"{'访问元素':<20}{'O(1)':<15}{'O(1)':<15}{'O(1)':<15}{'N/A':<15}")
print(f"{'搜索元素':<20}{'O(n)':<15}{'O(n)':<15}{'O(1)':<15}{'O(1)':<15}")
print(f"{'插入元素':<20}{'O(1)/O(n)*':<15}{'N/A':<15}{'O(1)':<15}{'O(1)':<15}")
print(f"{'删除元素':<20}{'O(1)/O(n)*':<15}{'N/A':<15}{'O(1)':<15}{'O(1)':<15}")
print("-" * 70)
print("* 列表在末尾操作是O(1),在开头或中间操作是O(n)")
输出结果(实际运行时间可能有所不同):
查找性能测试:
列表查找耗时: 0.023438秒
集合查找耗时: 0.000998秒
字典查找耗时: 0.000999秒
集合比列表快: 23.5倍
字典比列表快: 23.5倍
常见操作的时间复杂度:
----------------------------------------------------------------------
操作 列表 元组 字典 集合
----------------------------------------------------------------------
访问元素 O(1) O(1) O(1) N/A
搜索元素 O(n) O(n) O(1) O(1)
插入元素 O(1)/O(n)* N/A O(1) O(1)
删除元素 O(1)/O(n)* N/A O(1) O(1)
----------------------------------------------------------------------
* 列表在末尾操作是O(1),在开头或中间操作是O(n)
4.6.4 实际应用案例¶
# 实际应用案例示例
# 案例1: 数据分析 - 统计文本中单词频率
def word_frequency_analysis(text):
"""分析文本中单词出现的频率"""
words = text.lower().split()
frequency = {}
for word in words:
word = word.strip('.,!?;:()"\'')
if word:
frequency[word] = frequency.get(word, 0) + 1
sorted_freq = sorted(frequency.items(), key=lambda x: x[1], reverse=True)
return sorted_freq
sample_text = """Python is a programming language that lets you work quickly and integrate systems more effectively.
Python is powerful and fast, plays well with others, runs everywhere, is friendly and easy to learn."""
print("案例1: 文本单词频率分析")
word_freq = word_frequency_analysis(sample_text)
print("前5个高频单词:")
for word, count in word_freq[:5]:
print(f" {word}: {count}次")
# 案例2: 数据去重与合并 - 合并用户数据
def merge_user_data(user_lists):
all_users = set()
for user_list in user_lists:
all_users.update(user_list)
return sorted(list(all_users))
users_site_a = ["user1", "user2", "user3", "user4"]
users_site_b = ["user2", "user3", "user5", "user6"]
users_site_c = ["user1", "user6", "user7"]
print("\n案例2: 用户数据合并与去重")
merged_users = merge_user_data([users_site_a, users_site_b, users_site_c])
print(f"合并后的唯一用户: {merged_users}")
print(f"唯一用户总数: {len(merged_users)}")
# 案例3: 数据结构组合 - 简单购物车系统
class ShoppingCart:
def __init__(self):
self.items = {}
def add_item(self, item_id, name, price, quantity=1):
self.items[item_id] = {
"name": name,
"price": price,
"quantity": quantity
}
def remove_item(self, item_id, quantity=1):
if item_id in self.items:
self.items[item_id]["quantity"] -= quantity
if self.items[item_id]["quantity"] <= 0:
del self.items[item_id]
def get_total(self):
return sum(item["price"] * item["quantity"] for item in self.items.values())
def __str__(self):
if not self.items:
return "购物车为空"
total = self.get_total()
cart_str = "购物车内容:\n"
cart_str += "-" * 50 + "\n"
cart_str += f"{'商品名称':<20}{'单价':<10}{'数量':<10}{'小计':<10}\n"
cart_str += "-" * 50 + "\n"
for item in self.items.values():
subtotal = item["price"] * item["quantity"]
cart_str += f"{item['name']:<20}{item['price']:<10}{item['quantity']:<10}{subtotal:<10.2f}\n"
cart_str += "-" * 50 + "\n"
cart_str += f"总计: {total:.2f} 元"
return cart_str
print("\n案例3: 购物车系统")
cart = ShoppingCart()
cart.add_item("p001", "Python编程入门", 79.0, 1)
cart.add_item("p002", "数据结构与算法", 85.5, 2)
cart.add_item("p003", "Web开发实战", 95.0, 1)
print(cart)
输出结果:
案例1: 文本单词频率分析
前5个高频单词:
and: 4次
is: 3次
python: 2次
to: 2次
you: 1次
案例2: 用户数据合并与去重
合并后的唯一用户: ['user1', 'user2', 'user3', 'user4', 'user5', 'user6', 'user7']
唯一用户总数: 7
案例3: 购物车系统
购物车内容:
--------------------------------------------------
商品名称 单价 数量 小计
--------------------------------------------------
Python编程入门 79.0 1 79.00
数据结构与算法 85.5 2 171.00
Web开发实战 95.0 1 95.00
--------------------------------------------------
总计: 345.00 元
总结¶
本章详细介绍了Python中的五种主要数据结构:字符串、列表、元组、字典和集合。每种数据结构都有其独特的特点和适用场景:
- 字符串:适用于文本处理,提供了丰富的字符串操作方法。
- 列表:适用于存储有序、可变的元素序列,支持各种操作和修改。
- 元组:适用于存储不可变的有序元素序列,可作为字典键或确保数据不被修改。
- 字典:适用于键值对映射,提供高效的查找和存储。
- 集合:适用于存储唯一元素,支持集合运算,高效的成员检测。
选择合适的数据结构应考虑:
- 数据的性质(有序/无序、可变/不可变)
- 需要执行的操作(访问、搜索、插入、