04.python哈希表
python哈希表
集合Set
集合,简称集。由任意个元素构成的集体。高级语言都实现了这个非常重要的数据结构类型。
Python中,它是可变的、无序的、不重复的元素的集合。
初始化
- set() -> new empty set object
- set(iterable) -> new set object
s1 = set()
s2 = set(range(5))
s3 = set([1, 2, 3])
s4 = set('abcdabcd')
s5 = {} # 这是什么?
s6 = {1, 2, 3}
s7 = {1, (1,)}
s8 = {1, (1,), [1]} # ?
元素性质
- 去重:在集合中,所有元素必须相异
- 无序:因为无序,所以不可索引
- 可哈希:Python集合中的元素必须可以hash,即元素都可以使用内建函数hash
- 目前学过不可hash的类型有:list、set、bytearray
 
- 可迭代:set中虽然元素不一样,但元素都可以迭代出来
增加
- add(elem)
- 增加一个元素到set中
- 如果元素存在,什么都不做
 
- update(*others)
- 合并其他元素到set集合中来
- 参数others必须是可迭代对象
- 就地修改
 
s = set()
s.add(1) s.update((1,2,3), [2,3,4])
删除
- remove(elem)
- 从set中移除一个元素
- 元素不存在,抛出KeyError异常。为什么是KeyError?
 
- discard(elem)
- 从set中移除一个元素
- 元素不存在,什么都不做
 
- pop() -> item
- 移除并返回任意的元素。为什么是任意元素?
- 空集返回KeyError异常
 
- clear()
- 移除所有元素
 
s = set(range(10))
s.remove(0)
#s.remove(11) # KeyError为什么
s.discard(11) s.pop()
s.clear()
修改
集合类型没有修改。因为元素唯一。如果元素能够加入到集合中,说明它和别的元素不一样。
所谓修改,其实就是把当前元素改成一个完全不同的元素,就是删除加入新元素。
索引
非线性结构,不可索引。
成员运算符in
print(10 in [1, 2, 3])
print(10 in {1, 2, 3})
上面2句代码,分别在列表和集合中搜索元素。如果列表和集合的元素都有100万个,谁的效率高?
IPython魔术方法
IPython内置的特殊方法,使用%百分号开头的
- % 开头是line magic
- %% 开头是 cell magic,notebook的cell
%timeit statement
-n 一个循环loop执行语句多少次
-r 循环执行多少次loop,取最好的结果
%%timeit setup_code
 * code....
# 下面写一行,列表每次都要创建,这样写不好
%timeit (-1 in list(range(100)))
# 下面写在一个cell中,写在setup中,列表创建一次
%%timeit l=list(range(1000000))
-1 in l
set和线性结构比较

结果说明,集合性能很好。为什么?
- 线性数据结构,搜索元素的时间复杂度是O(n),即随着数据规模增加耗时增大
- set、dict使用hash表实现,内部使用hash值作为key,时间复杂度为O(1),查询时间和数据规模无关,不会随着数据规模增大而搜索性能下降。
遍历
只要是容器,都可以遍历元素。但是效率都是O(n)
可哈希
- 数值型int、float、complex
- 布尔型True、False
- 字符串string、bytes
- tuple
- None
- 以上都是不可变类型,称为可哈希类型,hashable
set元素必须是可hash的。
集合概念
- 全集
- 所有元素的集合。例如实数集,所有实数组成的集合就是全集
 
- 子集subset和超集superset
- 一个集合A所有元素都在另一个集合B内,A是B的子集,B是A的超集
 
- 真子集和真超集
- A是B的子集,且A不等于B,A就是B的真子集,B是A的真超集
 
- 并集:多个集合合并的结果
- 交集:多个集合的公共部分
- 差集:集合中除去和其他集合公共部分
并集

将两个集合A和B的所有的元素合并到一起,组成的集合称作集合A与集合B的并集
- union(*others) 返回和多个集合合并后的新的集合
- | 运算符重载,等同union
- update(*others) 和多个集合合并,就地修改
- |= 等同update
交集

集合A和B,由所有属于A且属于B的元素组成的集合
- intersection(*others) 返回和多个集合的交集
- & 等同intersection
- intersection_update(*others) 获取和多个集合的交集,并就地修改
- &= 等同intersection_update
差集

集合A和B,由所有属于A且不属于B的元素组成的集合
- difference(*others) 返回和多个集合的差集
- - 等同difference
- difference_update(*others) 获取和多个集合的差集并就地修改
- -= 等同difference_update
对称交差

集合A和B,由所有不属于A和B的交集元素组成的集合,记作(A-B)∪(B-A)
- symmetric_differece(other) 返回和另一个集合的对称差集
- ^ 等同symmetric_differece
- symmetric_differece_update(other) 获取和另一个集合的对称差集并就地修改
- ^= 等同symmetric_differece_update
其它集合运算
- issubset(other)、<= 判断当前集合是否是另一个集合的子集
- set1 < set2 判断set1是否是set2的真子集
- issuperset(other)、>= 判断当前集合是否是other的超集
- set1 > set2 判断set1是否是set2的真超集
- isdisjoint(other) 当前集合和另一个集合没有交集,没有交集,返回True
练习
- 一个总任务列表,存储所有任务。一个已完成的任务列表。找出为未完成的任务
业务中,任务ID一般不可以重复
所有任务ID放到一个set中,假设为ALL
所有已完成的任务ID放到一个set中,假设为COMPLETED,它是ALL的子集
ALL - COMPLETED => UNCOMPLETED
集合运算,用好了妙用无穷。
字典Dict
Dict即Dictionary,也称为mapping。
Python中,字典由任意个元素构成的集合,每一个元素称为Item,也称为Entry。这个Item是由(key, value)组成的二元组。
字典是可变的、无序的、key不重复的key-value pairs键值对集合。
初始化
- dict(**kwargs) 使用name=value对初始化一个字典 
- dict(iterable, **kwarg) 使用可迭代对象和name=value对构造字典,不过可迭代对象的元素必须是一个二元结构 
- dict(mapping, **kwarg) 使用一个字典构建另一个字典 
字典的初始化方法都非常常用,都需要会用
d1 = {}
d2 = dict()
d3 = dict(a=100, b=200)
d4 = dict(d3) # 构造另外一个字典
d5 = dict(d4, a=300, c=400)
d6 = dict([('a', 100), ['b', 200], (1, 'abc')], b=300, c=400)
# 类方法dict.fromkeys(iterable, value)
d = dict.fromkeys(range(5))
d = dict.fromkeys(range(5), 0)
元素访问
- d[key]
- 返回key对应的值value
- key不存在抛出KeyError异常
 
- get(key[, default])
- 返回key对应的值value
- key不存在返回缺省值,如果没有设置缺省值就返回None
 
- setdefault(key[, default])
- 返回key对应的值value
- key不存在,添加kv对,value设置为default,并返回default,如果default没有设置,缺省为None
 
新增和修改
- d[key] = value
- 将key对应的值修改为value
- key不存在添加新的kv对
 
- update([other]) -> None
- 使用另一个字典的kv对更新本字典
- key不存在,就添加
- key存在,覆盖已经存在的key对应的值
- 就地修改
 
d = {}
d['a'] = 1 d.update(red=1) d.update(['red', 2])
d.update({'red':3})
删除
- pop(key[, default])
- key存在,移除它,并返回它的value
- key不存在,返回给定的default
- default未设置,key不存在则抛出KeyError异常
 
- popitem()
- 移除并返回一个任意的键值对
- 字典为empty,抛出KeyError异常
 
- clear()
- 清空字典
 
遍历
1、遍历Key
for k in d:
    print(k)
for k in d.keys():
    print(k)
2、遍历Value
for v in d.values():
    print(v)
for k in d.keys():
    print(d[k])
    print(d.get(k))
3、遍历Item
for item in d.items():
    print(item)
    print(item[0], item[1])
for k,v in d.items():
    print(k, v)
for k,_ in d.items():
    print(k)
for _,v in d.items():
    print(v)
Python3中,keys、values、items方法返回一个类似一个生成器的可迭代对象
- Dictionary view对象,可以使用len()、iter()、in操作
- 字典的entry的动态的视图,字典变化,视图将反映出这些变化
- keys()返回一个类set对象,也就是可以看做一个set集合。如果values()都可以hash,那么items()也可以看做是类set对象
Python2中,上面的方法会返回一个新的列表,立即占据新的内存空间。所以Python2建议使用iterkeys、itervalues、iteritems版本,返回一个迭代器,而不是返回一个copy
遍历与删除
# 错误的做法
d = dict(a=1, b=2, c=3)
for k,v in d.items():
    print(d.pop(k))
抛出RuntimeError: dictionary changed size during iteration
在使用keys、values、items方法遍历的时候,不可以改变字典的size
while len(d):
    print(d.popitem())
while d:
    print(d.popitem())
上面的while循环虽然可以移除字典元素,但是很少使用,不如直接clear。
# for 循环正确删除
d = dict(a=1, b=2, c=3)
keys = []
for k,v in d.items():
keys.append(k)
for k in keys:
    d.pop(k)
集合set在遍历中,也不能改变其长度。
key
字典的key和set的元素要求一致
- set的元素可以就是看做key,set可以看做dict的简化版
- hashable 可哈希才可以作为key,可以使用hash()测试
- 使用key访问,就如同列表使用index访问一样,时间复杂度都是O(1),这也是最好的访问元素的方式
if __name__ == '__main__':
    d = {
     1: 0,
     2.0: 3,
     "abc": None,
     ('hello', 'world', 'python'): "string",
     b'abc': '135'
    }
有序性
字典元素是按照key的hash值无序存储的。
但是,有时候我们却需要一个有序的元素顺序,Python 3.6之前,使用OrderedDict类可以做到,3.6开 始dict自身支持。到底Python对一个无序数据结构记录了什么顺序?
# 3.5如下
C:\Python\Python353>python
Python 3.5.3 (v3.5.3:1880cb95a742, Jan 16 2017, 16:02:32) [MSC v.1900 64 bit
(AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> d = {'a':300, 'b':200, 'c':100, 'd':50}
>>> d
{'c': 100, 'a': 300, 'b': 200, 'd': 50}
>>> d
{'c': 100, 'a': 300, 'b': 200, 'd': 50}
>>> list(d.keys())
['c', 'a', 'b', 'd']
>>> exit()
C:\Python\Python353>python
Python 3.5.3 (v3.5.3:1880cb95a742, Jan 16 2017, 16:02:32) [MSC v.1900 64 bit
(AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> d = {'a':300, 'b':200, 'c':100, 'd':50}
>>> d
{'b': 200, 'c': 100, 'd': 50, 'a': 300}
Python 3.6之前,在不同的机器上,甚至同一个程序分别运行2次,都不能确定不同的key的先后顺序。
# 3.6+表现如下
C:\Python\python366>python
Python 3.6.6 (v3.6.6:4cf1f54eb7, Jun 27 2018, 03:37:03) [MSC v.1900 64 bit
(AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> d = {'c': 100, 'a': 300, 'b': 200, 'd': 50}
>>> d
{'c': 100, 'a': 300, 'b': 200, 'd': 50}
>>> exit()
C:\Python\python366>python
Python 3.6.6 (v3.6.6:4cf1f54eb7, Jun 27 2018, 03:37:03) [MSC v.1900 64 bit
(AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> d = {'c': 100, 'a': 300, 'b': 200, 'd': 50}
>>> d
{'c': 100, 'a': 300, 'b': 200, 'd': 50}
>>> d.keys()
dict_keys(['c', 'a', 'b', 'd'])
Python 3.6+,记录了字典key的录入顺序,遍历的时候,就是按照这个顺序。
如果使用 d = {'a':300, 'b':200, 'c':100, 'd':50} ,就会造成以为字典按照key排序的错觉。
目前,建议不要3.6+提供的这种字典特性,还是认为字典返回的是无序的,可以在Python不同版本中考虑使用OrderedDict类来保证这种录入序。
04.python哈希表的更多相关文章
- Python哈希表的例子:dict、set
		dict(字典) Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度. 和list比较,dic ... 
- Python哈希表和解析式
		目录 1. 封装和解构 1.1 封装 1.2 解构 2. 集合Set 2.1 初始化 2.2 增加 2.3 删除 2.4 遍历 2.5 并集&交集&差集&对称差集 3.字典 3 ... 
- python数据结构与算法——哈希表
		哈希表 学习笔记 参考翻译自:<复杂性思考> 及对应的online版本:http://greenteapress.com/complexity/html/thinkcomplexity00 ... 
- 用python实现哈希表
		哈哈,这是我第一篇博客园的博客.尝试了一下用python实现的哈希表,首先处理冲突的方法是开放地址法,冲突表达式为Hi=(H(key)+1)mod m,m为表长. #! /usr/bin/env py ... 
- python数据结构之哈希表
		哈希表(Hash table) 众所周知,HashMap是一个用于存储Key-Value键值对的集合,每一个键值对也叫做Entry.这些个键值对(Entry)分散存储在一个数组当中,这个数组就是Has ... 
- 【Python算法】哈希存储、哈希表、散列表原理
		哈希表的定义: 哈希存储的基本思想是以关键字Key为自变量,通过一定的函数关系(散列函数或哈希函数),计算出对应的函数值(哈希地址),以这个值作为数据元素的地址,并将数据元素存入到相应地址的存储单元中 ... 
- 使用python实现哈希表、字典、集合
		哈希表 哈希表(Hash Table, 又称为散列表),是一种线性表的存储结构.哈希表由一个直接寻址表和一个哈希函数组成.哈希函数h(k)将元素关键字k作为自变量,返回元素的存储下标. 简单哈希函数: ... 
- python code practice(二):KMP算法、二分搜索的实现、哈希表
		1.替换空格 题目描述:请实现一个函数,将一个字符串中的每个空格替换成“%20”.例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy. 分析: 将长度为 ... 
- Python 中的哈希表
		Python 中的哈希表:对字典的理解 有没有想过,Python中的字典为什么这么高效稳定.原因是他是建立在hash表上.了解Python中的hash表有助于更好的理解Python,因为Pytho ... 
随机推荐
- Java设计模式—Proxy动态代理模式
			代理:设计模式 代理是一种常用的设计模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问.代理类负责为委托类预处理消息,过滤消息并转发消息,以及进行消息被委托类执行后的后续处理. 图 1. 代 ... 
- 一个统计 CPU 内存 硬盘 使用率的shell脚本
			一个统计 CPU 内存 硬盘 使用率的shell脚本,供大家学习参考 #!/bin/bash #This script is use for describle CPU Hard Memery Uti ... 
- Linux目录终章,单用户模式修改密码、环境变量、第三方软件安装
			目录 今日内容概要 内容详细 解析映射文件 磁盘挂载文件 开机加载脚本 系统启动级别 使用单用户模式修改密码 变量加载文件 登录提示信息 第三方软件安装目录(编译安装目录) 系统日志目录 保存系统运行 ... 
- C#中继承和多态
			1.继承的概念 继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用已存在的类的功能. 为了提高软件模块的可复用性和可扩充性,以便提高软件的开发效率,我们总 ... 
- Mysql资料 Binlog
			目录 一.简介 二.开启binlog及相关参数 开启 相关操作 三.查看binlog日志 使用mysqlbinlog自带查看命令法 mysql加载方式查询 四.恢复数据 五.命令参数 一.简介 MyS ... 
- [BUUCTF]PWN——jarvisoj_level3_x64
			jarvisoj_level3_x64 附件 步骤: 例行检查,64位程序,开启了nx保护 试运行一下程序,看看大概的情况 64位ida载入,习惯性的检索字符串,没有发现可以直接利用的system,估 ... 
- YonBuilder低代码开发实践:4行代码实现跨实体列表数据同步
			提到增.删.改.查等数据维护,后端开发者们再熟悉不过了.传统的数据维护通过操作数据库的方式实现,步骤比较繁琐,需要通过Java代码实现数据库链接,然后编写SQL语句.编写实体,将想要的数据存到相应的数 ... 
- springmvc整合redis
			1.引入依赖 2.在resources包下创建配置文件redis-context.xml 3.在spring-servlet文件引入redis配置文件 
- CF749A Bachgold Problem 题解
			Content 给定一个数 \(n\),求它最多能够拆分成多少个质数,并输出拆分成的每一个质数. 数据范围:\(2\leqslant n\leqslant 10^5\). Solution 我们考虑尽 ... 
- CF581B Luxurious Houses 题解
			Content 一条大街上有 \(n\) 个房子,第 \(i\) 个房子的楼层数量是 \(h_i\).如果一个房子的楼层数量大于位于其右侧的所有房屋,则房屋是豪华的.对于第 \(i\) 个房子,请求出 ... 
