# 2. 映射

## 2.1. 散列函数 (hash)

### 2.1.1. 简单一致散列

• 简单一致假设: 元素散列到每个链表的可能性是相同的, 且与其他已被散列的元素独立无关.
• 简单一致散列 (simple uniform hashing): 满足简单一致假设的散列

* 各位相加
* 两位叠加
* 循环移位
* …

## 2.3. 链接法

### 2.3.1. 全域散列 (universal hashing)

#### 2.3.1.3. 实现

$h_{a,b}(k) = ((ak+b)mod\ p) mod\ m$
${H}_{p,m}=\left\{{h}_{a,b}|a\in {Z}_{p}^{\ast },b\in {Z}_{p}\right\}$$H_{p,m}=\{h_{a,b}|a\in Z_p^{*},b\in Z_p\}$

## 2.4. 开放寻址法

* 线性 $\ 0,1,\ldots,m-1$

* 二次 $\ 0,1,\ldots,(m-1)^2$

* 双重探查
$h(k,i) = (h_1(k)+i*h_2(k))mod\ m$

### 2.4.1. 不成功查找的探查数的期望

$p\left(\text{不成功探查}\right)=p\left(\text{第一次找到空槽}\right)=\frac{m-n}{m}$

$E\left(\text{探查数}\right)=\frac{1}{p}⩽\frac{1}{1-\alpha }$

#### 2.4.1.2. 成功查找的探查数的期望

$\frac{1}{1-\alpha }=\frac{1}{1-\frac{i}{m}}=\frac{m}{m-i}$

$\begin{array}{rl}\frac{1}{n}\sum _{i=0}^{n-1}\frac{m}{m-i}=\frac{m}{n}\sum _{i=0}^{n-1}\frac{1}{m-i}& =\frac{m}{n}\sum _{i=m-n+1}^{m}\frac{1}{i}\\ & ⩽\frac{1}{\alpha }{\int }_{m-n}^{m}\frac{1}{x}dx\\ & =\frac{1}{\alpha }ln\frac{1}{1-\alpha }\end{array}$

github 地址

class item:
def __init__(self,key,val,nextItem=None):
self.key = key
self.val = val
self.next = nextItem
def to(self,it):
self.next = it
def __eq__(self,it):
'''using  keyword <in> '''
return self.key == it.key
def __bool__(self):
return self.key is not None
def __str__(self):
li = []
nd = self
while nd:
li.append(f'({nd.key}:{nd.val})')
nd = nd.next
return ' -> '.join(li)
def __repr__(self):
return f'item({self.key},{self.val})'
class hashTable:
def __init__(self,size=100):
self.size = size
self.slots=[item(None,None) for i in range(self.size)]
def __setitem__(self,key,val):
nd = self.slots[self.myhash(key)]
while nd.next:
if nd.key ==key:
if nd.val!=val: nd.val=val
return
nd  = nd.next
nd.next = item(key,val)

def myhash(self,key):
if isinstance(key,str):
key = sum(ord(i) for i in key)
if not isinstance(key,int):
key = hash(key)
return key % self.size
def __iter__(self):
'''when using keyword <in>, such as ' if key in dic',
the dic's  __iter__ method will be called,(if hasn't, calls __getitem__
then  ~iterate~  dic's keys to compare whether one equls to the key
'''
for nd in self.slots:
nd = nd.next
while nd :
yield nd.key
nd = nd.next
def __getitem__(self,key):
nd =self.slots[ self.myhash(key)].next
while nd:
if nd.key==key:
return nd.val
nd = nd.next
raise Exception(f'[KeyError]: {self.__class__.__name__} has no key {key}')

def __delitem__(self,key):
'''note that None item and item(None,None) differ with each other,
which means you should take care of them and correctly cop with None item
especially when deleting items
'''
n = self.myhash(key)
nd = self.slots[n].next
if nd.key == key:
if nd.next is None:
self.slots[n] =  item(None,None) # be careful
else:self.slots[n] = nd.next
return
while nd:
if nd.next is None: break  # necessary
if nd.next.key ==key:
nd.next = nd.next.next
nd = nd.next
def __str__(self):
li = ['\n\n'+'-'*5+'hashTable'+'-'*5]
for i,nd in enumerate(self.slots):
li.append(f'{i}: '+str(nd.next))
return '\n'.join(li)