目录
背景
散列:Hashing
- 由前所述,如果数据项按照大小排好序,采用二分查找降低算法复杂度
- 构造新的数据结构,使得查找算法的复杂度降低到O(1)
- 需要对数据项所处的位置有更多的先验知识
散列表 Hash table
- 每一个存储位置——槽,每个槽都有唯一的名称
采用求余数的方法,得到散列表
- 负载因子:槽被数据项占的比例
完美散列函数
如果一个散列函数能把每个数据项都映射到不同的槽中,那么这个散列函数称为”完美散列函数“
数据项经常变动,如何设计完美散列函数?
好的散列函数具备特性
- 冲突最少(近似完美)
- 计算难度低(额外开销小)
- 充分分散数据项(节约空间)
应用
”指纹函数“
- 压缩性——任意长度的数据得到的”指纹“长度固定
- 易计算性——从原数据计算”指纹“很容易,从指纹计算原数据几乎不可能
- 抗修改性——对原数据的微小改动都会引起”指纹"的巨大改变
- 抗冲突性——已知原数据和“指纹”,要找到相同指纹的数据(伪造)非常困难
例子
import hashlib
hashlib.md5("hello world!").hexdigest()
hashlib.sha1("hello world!").hexdigest()
# 还可以用update方法
m = hashlib.md5()
m.update("hello world!")
m.update("this is part #2")
m.hexdigest()
- 加密形式保存密码
- 防止文件篡改
- 彩票投注应用
散列函数的最酷应用——区块链
含义
区块链是一种分布式数据库
通过网络连接的节点,每个节点都保存着整个数据库的所有数据,任何地点存入的数据都会完成同步
本质特征
去中心化:不存在任何控制中心,协调中心节点。所有的节点都是平等的,无法被控制
工作量证明:谁的工作量大谁就掌握全网的修改;
散列计算不是非常容易计算吗?为什么要付出海量计算?
因为难以计算,所以控制了新区块生成的速度,便于在整个分布式网络中同步
散列函数的设计
折叠法
平方取中法
非数项处理
增加权重是处理变位词的好办法,但增加了计算量
因此,散列函数不能成为存储过程和查找过程的计算负担,否则直接做顺序查找、二分查找即可
散列冲突解决方案
跳跃式探测方法
再散列
散列表的长度设置为质数,保证均匀分布
二次探测
数据项链——散列和列表的折中,O(1)和O(n)的折中
映射抽象数据类型和其实现
抽象数据类型“映射”:ADT Map
代码示例
H=HashTable()
H[54]="cat"
H[24]="dog"
print(H.slots)
print(H.data)
print(H[24]) # dog
print(H[20]) # None
class HashTable:
def __init__(self):
self.size = 11
self.slots = [None]*self.size
self.data = [None]*self.size