python数据结构与算法-08_字典

字典 dict

上一章我们介绍了哈希表,其实 python 内置的 dict 就是用哈希表实现的,所以这一章实现 dict 就非常简单了。
当然 cpython 使用的是 c 语言实现的,远比我们写的复杂得多 (cpython/Objects/dictobject.c)。
上一章我们用 python 自己写的一个 Array 来代表定长数组,然后用它实现的 HashTable,它支持三个最基本的方法

  • add(key ,value): 有 key 则更新,否则插入
  • get(key, default=None): 或者 key 的值,不存在返回默认值 None
  • remove(key): 删除一个 key,这里其实不是真删除,而是标记为 Empty

字典最常使用的场景就是 k,v 存储,经常用作缓存,它的 key 值是唯一的。
内置库 collections.OrderedDict 还保持了 key 的添加顺序,其实用我们之前实现的链表也能自己实现一个 OrderedDict。

实现 dict ADT

其实上边 HashTable 实现的三个基本方法就是我们使用字典最常用的三个基本方法, 这里我们继承一下这个类,
然后实现更多 dict 支持的方法,items(), keys(), values()。不过需要注意的是,在 python2 和 python3 里这些方法
的返回是不同的,python3 里一大改进就是不再返回浪费内存的 列表,而是返回迭代器,你要获得列表必须用 list() 转换成列表。 这里我们实现 python3 的方式返回迭代器。

class DictADT(HashTable):pass

视频里我们将演示如何实现这些方法,并且写单测验证正确性。

Hashable

作为 dict 的 key 必须是可哈希的,也就是说不能是 list 等可变对象。不信你在 ipython 里运行如下代码:

d = dict()
d[[1]] = 1
# TypeError: unhashable type: 'list'

我引用 python 文档里的说法,大家可以自己理解下:

An object is hashable if it has a hash value which never changes during its lifetime (it needs a __hash__() method), and can be compared to other objects (it needs an __eq__() or __cmp__() method). Hashable objects which compare equal must have the same hash value.Hashability makes an object usable as a dictionary key and a set member, because these data structures use the hash value internally.All of Python’s immutable built-in objects are hashable, while no mutable containers (such as lists or dictionaries) are. Objects which are instances of user-defined classes are hashable by default; they all compare unequal (except with themselves), and their hash value is derived from their id().

源码

# -*- coding: utf-8 -*-# 从数组和列表章复制的代码class Array(object):def __init__(self, size=32, init=None):self._size = sizeself._items = [init] * sizedef __getitem__(self, index):return self._items[index]def __setitem__(self, index, value):self._items[index] = valuedef __len__(self):return self._sizedef clear(self, value=None):for i in range(len(self._items)):self._items[i] = valuedef __iter__(self):for item in self._items:yield itemclass Slot(object):"""定义一个 hash 表 数组的槽注意,一个槽有三种状态,看你能否想明白。相比链接法解决冲突,二次探查法删除一个 key 的操作稍微复杂。1.从未使用 HashMap.UNUSED。此槽没有被使用和冲突过,查找时只要找到 UNUSED 就不用再继续探查了2.使用过但是 remove 了,此时是 HashMap.EMPTY,该探查点后边的元素扔可能是有key3.槽正在使用 Slot 节点"""def __init__(self, key, value):self.key, self.value = key, valueclass HashTable(object):UNUSED = None  # 没被使用过EMPTY = Slot(None, None)  # 使用却被删除过def __init__(self):self._table = Array(8, init=HashTable.UNUSED)   # 保持 2*i 次方self.length = 0@propertydef _load_factor(self):# load_factor 超过 0.8 重新分配return self.length / float(len(self._table))def __len__(self):return self.lengthdef _hash(self, key):return abs(hash(key)) % len(self._table)def _find_key(self, key):index = self._hash(key)_len = len(self._table)while self._table[index] is not HashTable.UNUSED:if self._table[index] is HashTable.EMPTY:index = (index*5 + 1) % _lencontinueelif self._table[index].key == key:return indexelse:index = (index*5 + 1) % _lenreturn Nonedef _find_slot_for_insert(self, key):index = self._hash(key)_len = len(self._table)while not self._slot_can_insert(index):index = (index*5 + 1) % _lenreturn indexdef _slot_can_insert(self, index):return (self._table[index] is HashTable.EMPTY or self._table[index] is HashTable.UNUSED)def __contains__(self, key):  # in operatorindex = self._find_key(key)return index is not Nonedef add(self, key, value):if key in self:index = self._find_key(key)self._table[index].value = valuereturn Falseelse:index = self._find_slot_for_insert(key)self._table[index] = Slot(key, value)self.length += 1if self._load_factor >= 0.8:self._rehash()return Truedef _rehash(self):old_table = self._tablenewsize = len(self._table) * 2self._table = Array(newsize, HashTable.UNUSED)self.length = 0for slot in old_table:if slot is not HashTable.UNUSED and slot is not HashTable.EMPTY:index = self._find_slot_for_insert(slot.key)self._table[index] = slotself.length += 1def get(self, key, default=None):index = self._find_key(key)if index is None:return defaultelse:return self._table[index].valuedef remove(self, key):index = self._find_key(key)if index is None:raise KeyError()value = self._table[index].valueself.length -= 1self._table[index] = HashTable.EMPTYreturn valuedef __iter__(self):for slot in self._table:if slot not in (HashTable.EMPTY, HashTable.UNUSED):yield slot.key#########################################
# 上边是从 哈希表章 拷贝过来的代码,我们会直接继承 HashTable 实现 dict
#########################################class DictADT(HashTable):def _iter_slot(self):for slot in self._table:if slot not in (HashTable.EMPTY, HashTable.UNUSED):yield slotdef __setitem__(self, key, value):self.add(key, value)def __getitem__(self, key):if key not in self:raise KeyError()else:return self.get(key)def items(self):for slot in self._iter_slot():yield (slot.key, slot.value)def keys(self):for slot in self._iter_slot():yield slot.keydef values(self):for slot in self._iter_slot():yield slot.valuedef test_dict_adt():import randomd = DictADT()d['a'] = 1assert d['a'] == 1d.remove('a')l = list(range(30))random.shuffle(l)for i in l:d.add(i, i)for i in range(30):assert d.get(i) == iassert sorted(list(d.keys())) == sorted(l)test_dict_adt()

思考题:

  • 你能在哈希表的基础上实现 dict 的其他操作吗?
  • 对于 python 来说,哪些内置数据类型是可哈希的呢?list, dict, tuple, set 等类型哪些可以作为字典的 key 呢?
  • 你了解可变对象和不可变对象的区别吗?
  • 你了解 python 的 hash 函数吗?你了解 python 的__hash____eq__ 魔术方法吗?它们何时被调用

延伸阅读

阅读 python 文档关于 dict 的相关内容

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/153458.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

电容搞搞”振“,PDN有帮衬

高速先生成员--姜杰 聊电容,不能只聊电容,还要聊电阻和电感。看似很简单,其实,一点都不难。 因为去耦电容的模型基本都可以用下面三种元素的简单组合来表示。 理想电容C的阻抗是随频率的增加而逐渐减小的一条斜线,实际…

脱离form表单校验input(校验单个input输入框)提交时边框变红

把需要自定义校验的数据放在一个对象中&#xff0c;方便以后多个字段校验 customVerifyInps:{communityInp2:"",asPathInp:"",}, 在输入框中绑定id <el-inputid"communityInp2"placeholder""v-model"customVerifyInps.commu…

基于STM32设计的(无人)智慧超市-2023改进版

改进的内容: 增加了一个智慧超市登录入口,整个上位机只有一个APP文件。 可以选择顾客或者管理员的身份进去。优化了界面的显示。 一、项目背景 智慧超市是一种新型的零售形式,它将人工智能、物联网、云计算等技术应用到超市运营中,为消费者提供更加便捷、快捷、个性化的购…

IF:9.0+期刊被踢除,11月SCI/SSCI期刊目录已更新!

【SciencePub学术】2023年11月20日&#xff0c;科睿唯安更新了Web of Science核心期刊目录。 继上次SCI期刊目录和SSCI期刊目录更新之后&#xff0c;本次11月更新共有5本期刊发生变动&#xff1a; • SCIE&#xff1a;有5本期刊不再被SCIE期刊目录收录&#xff0c;1本SCIE期刊更…

Flask Web开发:数据库

目录 在虚拟环境中安装Flask-SQLAlchemy&#xff1a; 一、配置 数据库配置示例&#xff1a; 二、定义模型 Role 和 User 模型代码&#xff1a; &#xff08;1&#xff09;常用的 SQLAlchemy 列类型&#xff1a;​编辑 &#xff08;2&#xff09;常用的 SQLAlchemy 列选项…

手撕单链表(C语言)

目录 1.单链表的物理结构 2.头文件的实现 3.SList.c文件的实现 3.1尾插、创建节点 3.2打印 3.3头插 3.4尾删 3.5头删 3.6查找 3.7指定位置之前插入数据 3.8指定位置之后插入数据 3.9删除指定位置节点 3.10删除pos之后的节点 3.11销毁链表 4 所有的代码 1.单链表的物理结构 众所…

Linux删除文件后没有释放空间解决办法

执行下列命令查看处于deleted状态的进程&#xff0c;然后杀掉进程。 lsof | grep deleted注&#xff1a;没有lsof命令的安装一下。 yum install lsof -y

第十篇 基于JSP 技术的网上购书系统——管理员后台管理主界面、订单管理、产品管理功能实现(网上商城、仿淘宝、当当、亚马逊)

目录 1.管理员后台管理——主界面 1.1功能说明 1.2界面设计 1.3处理流程 2.订单管理 2.1功能说明 2.2界面设计 2.3处理流程 2.4数据来源和算法 2.4.1数据来源 2.4.2查询条件 2.4.3表间关系 2.4.4相关sql实例 3.产品管理 3.1功能说明 3.2界面设计 3.3处理流程…

Mybatis系列之 parameterMap 弃用了

我 | 在这里 &#x1f575;️ 读书 | 长沙 ⭐软件工程 ⭐ 本科 &#x1f3e0; 工作 | 广州 ⭐ Java 全栈开发&#xff08;软件工程师&#xff09; &#x1f383; 爱好 | 研究技术、旅游、阅读、运动、喜欢流行歌曲 &#x1f3f7;️ 标签 | 男 自律狂人 目标明确 责任心强 ✈️公…

2023,阿里巴巴走向了中年的十字路口

双十一刚过&#xff0c;各互联网巨头便纷纷对外公布了财报。结合数据来看&#xff0c;虽然行业整体很难重回巅峰&#xff0c;但保持在一个合理的增长区间之内仍是可能的。以阿里为例&#xff0c;在经过持续的整顿调整之后&#xff0c;今年第三季度阿里的“业绩”已有了喜人的变…

【视觉SLAM十四讲学习笔记】第三讲——旋转矩阵

专栏系列文章如下&#xff1a; 【视觉SLAM十四讲学习笔记】第一讲——SLAM介绍 【视觉SLAM十四讲学习笔记】第二讲——初识SLAM 本章将介绍视觉SLAM的基本问题之一&#xff1a;如何描述刚体在三维空间中的运动&#xff1f; 旋转矩阵 点、向量和坐标系 三维空间由3个轴组成&…

担忧CentOS停服?KeyarchOS系统来支撑

担忧CentOS停服&#xff1f;KeyarchOS系统来支撑 近年发生的“微软黑屏门”、“微软操作系统停更”等安全事件&#xff0c;敲响了我国 IT 产业的警钟&#xff0c;建立由我国主导的 IT 产业生态尤为迫切。对此&#xff0c;我国信息技术应用创新行业乘势而起&#xff0c;旨在通过…

给Fetch添加超时功能

引言 在Web开发中&#xff0c;使用Fetch API进行网络请求是一种常见的方式。然而&#xff0c;Fetch API默认不包含超时功能&#xff0c;这可能导致程序在网络不稳定的情况下长时间阻塞。为了解决这个问题&#xff0c;我们可以通过一些技术手段来为Fetch请求添加超时功能&#…

使用大语言模型 LLM 做文本分析

本文主要分享 传统聚类算法 LLM与嵌入算法 嵌入算法聚类 LLM的其他用法 聚类是一种无监督机器学习技术&#xff0c;旨在根据相似的数据点的特征将其分组在一起。使用聚类成簇&#xff0c;有助于解决各种问题&#xff0c;例如客户细分、异常检测和文本分类等。尽管传统的聚…

vue3插槽的使用

什么是插槽 Vue 3 插槽&#xff08;Slots&#xff09;是一个强大的工具&#xff0c;用于在组件之间传递内容和逻辑。通过使用插槽&#xff0c;我们可以将子组件中的内容插入到父组件中的特定位置。本篇文章将总结 Vue 3 插槽的基本用法、特点以及使用场景。 基本用法 插槽分为…

DSCNet:基于拓扑几何约束的动态蛇形卷积管状结构分割

文章目录 摘要1、简介2、相关研究2.1、基于网络设计的方法2.2、基于特征融合的方法2.3、基于损失函数的方法 3、方法3.1、动态蛇形卷积&#xff08;Dynamic Snake Convolution&#xff09;3.2、多视图特征融合策略3.3、拓扑连续性约束损失 4、实验配置4.1、数据集4.2、评估指标…

Redis篇---第十一篇

系列文章目录 文章目录 系列文章目录前言一、说说Redis持久化机制二、缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题三、热点数据和冷数据是什么前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章…

宇视科技通过stm32叠加字符串

void sendtoYskj(uint8_t *cameraIp,uint16_t cameraSrcPort,uint16_t cameraDstPort,uint8_t *userName,uint8_t *pwd,uint8_t lineNum,int camNo)//宇视科技 { int flag = 1; int sock = -1,connected; int send_data_len; int recv_data_len; //char str…

harmonyOS鸿蒙开发工具下载安装以及使用流程

注册账号 进入鸿蒙官方网站&#xff1a;https://www.harmonyos.com/ 推荐使用手机号注册 进行实名认证 发布工具 华为集成开发环境IDE DevEco Device Tool下载 | HarmonyOS设备开发 下载开发工具 HUAWEI DevEco Studio和SDK下载和升级 | HarmonyOS开发者 安装 无脑下一步选…