数据结构:字典

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

概述

  • 在数据结构中,字典(Dictionary) 是一种键值对(Key-Value Pair) 存储的数据结构,核心特性是通过键(Key) 快速查找对应值(Value),不依赖元素的插入顺序。
  • 注意:字典与我们之前讲的散列表(哈希表) 关系密切——散列表是字典的底层实现方式(绝大多数编程语言中),而字典是面向开发者的抽象数据类型(ADT),定义了键值对的操作接口(如增删改查)。
  • 资料:https://pan.quark.cn/s/43d906ddfa1b

一、字典的核心特点

  1. 键唯一:每个键在字典中只能出现一次,重复插入相同键会覆盖对应的值;
  2. 键不可变:键必须是不可变类型(如整数、字符串、元组),不能用列表、字典等可变类型作为键;
  3. 无序性(传统字典):早期字典不保证元素的存储顺序(如Python 3.6之前),现代实现(Python 3.7+、Java HashMap)会保留插入顺序,但这不是字典的核心定义;
  4. 高效查找:平均时间复杂度 O(1),底层依赖散列表的哈希映射机制。

二、字典的基本操作

字典的操作围绕“键值对”展开,核心操作如下:

操作描述时间复杂度(平均)
insert(key, value)插入键值对,键已存在则更新值O(1)
get(key)根据键查找值,键不存在返回 None 或抛异常O(1)
delete(key)根据键删除键值对,键不存在返回 FalseO(1)
contains(key)判断键是否存在于字典中O(1)
keys()返回所有键的集合O(n)
values()返回所有值的集合O(n)
items()返回所有键值对的集合O(n)
size()返回字典中键值对的数量O(1)
clear()清空字典所有元素O(n)

三、字典的底层实现(与散列表的关系)

字典的高效性完全依赖散列表(哈希表) 的实现,两者的对应关系:

  1. 字典的“键(Key)” → 散列表的“键”,通过哈希函数计算索引;
  2. 字典的“值(Value)” → 散列表中存储的“数据”;
  3. 字典的“键唯一” → 散列表中相同哈希值的键会通过冲突解决策略处理(如链地址法),确保键的唯一性。

简单说:字典是散列表的“上层应用”,散列表提供了底层存储和查找能力,字典则封装了键值对的操作逻辑,更贴近开发者的使用场景。

四、字典的实现(Python示例)

Python 中的 dict 是字典的经典实现(底层为散列表),直接使用即可满足绝大多数需求。以下是自定义简易字典(基于散列表的链地址法),帮助理解底层逻辑:

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']

五、字典的优缺点

优点
  1. 查找高效:平均 O(1) 时间复杂度,远快于数组、链表的 O(n);
  2. 使用直观:键值对映射符合人类认知(如“名字→值”“ID→用户信息”);
  3. 操作便捷:支持插入、更新、删除等完整操作,接口友好。
缺点
  1. 无序性(传统实现):无法直接按插入顺序或大小顺序遍历(现代实现已优化);
  2. 内存开销大:底层散列表需要额外空间存储桶和链表指针,空间利用率低于数组;
  3. 键不可变:限制了键的类型,灵活性不如某些数据结构;
  4. 最坏性能差:哈希冲突严重时,查找时间复杂度退化为 O(n)(需依赖良好的哈希函数和扩容策略)。

六、字典的应用场景

字典是工程中最常用的数据结构之一,典型场景:

  1. 配置存储:存储系统配置(如 {"host": "localhost", "port": 8080});
  2. 缓存数据:临时存储高频访问数据(如用户会话信息);
  3. 数据索引:为大量数据建立键索引(如学生ID→学生信息);
  4. 词频统计:统计文本中单词出现次数(如 {"apple": 5, "banana": 3});
  5. 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)即可,这些实现已优化了哈希函数、冲突解决和扩容策略,性能稳定且易用。

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值