概述
- 在数据结构中,字典(Dictionary) 是一种键值对(Key-Value Pair) 存储的数据结构,核心特性是通过键(Key) 快速查找对应值(Value),不依赖元素的插入顺序。
- 注意:字典与我们之前讲的散列表(哈希表) 关系密切------散列表是字典的底层实现方式 (绝大多数编程语言中),而字典是面向开发者的抽象数据类型(ADT),定义了键值对的操作接口(如增删改查)。
- 资料:
https://pan.quark.cn/s/43d906ddfa1b
一、字典的核心特点
- 键唯一:每个键在字典中只能出现一次,重复插入相同键会覆盖对应的值;
- 键不可变:键必须是不可变类型(如整数、字符串、元组),不能用列表、字典等可变类型作为键;
- 无序性(传统字典):早期字典不保证元素的存储顺序(如Python 3.6之前),现代实现(Python 3.7+、Java HashMap)会保留插入顺序,但这不是字典的核心定义;
- 高效查找:平均时间复杂度 O(1),底层依赖散列表的哈希映射机制。
二、字典的基本操作
字典的操作围绕"键值对"展开,核心操作如下:
| 操作 | 描述 | 时间复杂度(平均) |
|---|---|---|
insert(key, value) |
插入键值对,键已存在则更新值 | O(1) |
get(key) |
根据键查找值,键不存在返回 None 或抛异常 |
O(1) |
delete(key) |
根据键删除键值对,键不存在返回 False |
O(1) |
contains(key) |
判断键是否存在于字典中 | O(1) |
keys() |
返回所有键的集合 | O(n) |
values() |
返回所有值的集合 | O(n) |
items() |
返回所有键值对的集合 | O(n) |
size() |
返回字典中键值对的数量 | O(1) |
clear() |
清空字典所有元素 | O(n) |
三、字典的底层实现(与散列表的关系)
字典的高效性完全依赖散列表(哈希表) 的实现,两者的对应关系:
- 字典的"键(Key)" → 散列表的"键",通过哈希函数计算索引;
- 字典的"值(Value)" → 散列表中存储的"数据";
- 字典的"键唯一" → 散列表中相同哈希值的键会通过冲突解决策略处理(如链地址法),确保键的唯一性。
简单说:字典是散列表的"上层应用",散列表提供了底层存储和查找能力,字典则封装了键值对的操作逻辑,更贴近开发者的使用场景。
四、字典的实现(Python示例)
Python 中的 dict 是字典的经典实现(底层为散列表),直接使用即可满足绝大多数需求。以下是自定义简易字典(基于散列表的链地址法),帮助理解底层逻辑:
python
class Dictionary:
def __init__(self, capacity=8):
self.capacity = capacity # 底层桶数组大小
self.buckets = [None] * self.capacity # 桶数组(每个桶存储链表)
self.size = 0 # 键值对数量
self.load_factor = 0.75 # 负载因子阈值
class Node:
"""字典节点(链表节点)"""
def __init__(self, key, value):
self.key = key
self.value = value
self.next = None
def _hash(self, key):
"""哈希函数:计算键的桶索引"""
return hash(key) % self.capacity
def _resize(self):
"""扩容:桶数组翻倍,重新哈希所有键值对"""
old_buckets = self.buckets
self.capacity *= 2
self.buckets = [None] * self.capacity
self.size = 0
# 重新插入旧桶中的所有键值对
for bucket in old_buckets:
current = bucket
while current:
self.insert(current.key, current.value)
current = current.next
def insert(self, key, value):
"""插入/更新键值对"""
# 检查是否需要扩容
if self.size / self.capacity >= self.load_factor:
self._resize()
index = self._hash(key)
current = self.buckets[index]
# 键已存在,更新值
while current:
if current.key == key:
current.value = value
return
current = current.next
# 键不存在,插入链表头部
new_node = self.Node(key, value)
new_node.next = self.buckets[index]
self.buckets[index] = new_node
self.size += 1
def get(self, key):
"""根据键查找值"""
index = self._hash(key)
current = self.buckets[index]
while current:
if current.key == key:
return current.value
current = current.next
return None # 键不存在
def delete(self, key):
"""根据键删除键值对"""
index = self._hash(key)
current = self.buckets[index]
prev = None
while current:
if current.key == key:
# 调整链表指针
if prev:
prev.next = current.next
else:
self.buckets[index] = current.next
self.size -= 1
return True
prev = current
current = current.next
return False # 键不存在
def contains(self, key):
"""判断键是否存在"""
return self.get(key) is not None
def keys(self):
"""返回所有键"""
key_list = []
for bucket in self.buckets:
current = bucket
while current:
key_list.append(current.key)
current = current.next
return key_list
def __str__(self):
"""打印字典"""
items = []
for bucket in self.buckets:
current = bucket
while current:
items.append(f"{current.key}: {current.value}")
current = current.next
return "{" + ", ".join(items) + "}"
# 使用示例
d = Dictionary()
d.insert("name", "Alice")
d.insert("age", 25)
d.insert("city", "Beijing")
d.insert("age", 26) # 更新age的值
print(d) # 输出: {name: Alice, age: 26, city: Beijing}
print(d.get("age")) # 输出: 26
print(d.contains("city")) # 输出: True
print(d.delete("city")) # 输出: True
print(d.keys()) # 输出: ['name', 'age']
五、字典的优缺点
优点
- 查找高效:平均 O(1) 时间复杂度,远快于数组、链表的 O(n);
- 使用直观:键值对映射符合人类认知(如"名字→值""ID→用户信息");
- 操作便捷:支持插入、更新、删除等完整操作,接口友好。
缺点
- 无序性(传统实现):无法直接按插入顺序或大小顺序遍历(现代实现已优化);
- 内存开销大:底层散列表需要额外空间存储桶和链表指针,空间利用率低于数组;
- 键不可变:限制了键的类型,灵活性不如某些数据结构;
- 最坏性能差:哈希冲突严重时,查找时间复杂度退化为 O(n)(需依赖良好的哈希函数和扩容策略)。
六、字典的应用场景
字典是工程中最常用的数据结构之一,典型场景:
- 配置存储 :存储系统配置(如
{"host": "localhost", "port": 8080}); - 缓存数据:临时存储高频访问数据(如用户会话信息);
- 数据索引:为大量数据建立键索引(如学生ID→学生信息);
- 词频统计 :统计文本中单词出现次数(如
{"apple": 5, "banana": 3}); - JSON/XML解析:JSON数据本质就是键值对,解析后常以字典形式存储。
七、字典 vs 散列表 vs 数组 vs 链表
| 数据结构 | 核心特性 | 查找效率 | 插入/删除效率 | 适用场景 |
|---|---|---|---|---|
| 字典 | 键值对映射、键唯一 | O(1)(平均) | O(1)(平均) | 快速查找、键值对存储 |
| 散列表 | 哈希映射、冲突解决 | O(1)(平均) | O(1)(平均) | 字典的底层实现 |
| 数组 | 连续存储、索引访问 | O(1)(索引) | O(n)(中间) | 有序数据、随机访问 |
| 链表 | 非连续存储、指针连接 | O(n) | O(1)(已知节点) | 频繁插入删除、无需随机访问 |
八、总结
字典是一种高效的键值对存储结构,底层依赖散列表实现,核心优势是"通过键快速查找值"。它平衡了时间效率和使用便捷性,是解决"映射查找"问题的首选数据结构。
实际开发中,无需自定义字典,直接使用编程语言内置实现(如 Python 的 dict、Java 的 HashMap、JavaScript 的 Object)即可,这些实现已优化了哈希函数、冲突解决和扩容策略,性能稳定且易用。