## 1. Direct-address tables

Assume all elements’ keys are different and are from $$U={0, 1, …, m-1}$$. Then the direct-address table is $$T[0..m-1]$$, that is to say, the key is the index.

DIRECT-ADDRESS-SEARCH(T,k)
return T[k]
DIRECT-ADDRESS-INSERT(T,x)
T[x.key]=x
DIRECT-ADDRESS-DELETE(T,x)
T[x.key]=NIL


## 2. Hash tables

The actual keys set $$K$$ is so small relative to the universe of keys set $$U$$. So a hash function should be used.

$$h: U\rightarrow \left \{0,1,…,m-1 \right \}$$

$$h(k)$$ is the hash value of $$k$$

Collision: Two keys may hash to the same slot.

Collision resolution by chaining

CHAINED-HASH-INSERT(T,x)
insert x at the head of list T[h(x,key)]
CHAINED-HASH-SEARCH(T,k)
search for an element with key k in list T[h(k)]
CHAINED-HASH-DELETE(T,x)
delete x from the list T[h(x,key)]


Load Factor $$\alpha=n/m$$

Insert: $$O(1)$$

Search:$$O(n)$$

Delete:$$O(1)$$

Simple Uniform Hashing:

For$$j=0,1,…,m-1$$, denote the length of $$T[j]$$ by  $$n_j$$, so that $$n=n_0+n_1+…+n_(m-1)$$. Then $$E[n_j]=\alpha=n/m$$.

If we assume simple uniform hashing, then the average-case time of search is $$\theta(1+\alpha)$$.

## 3. Hash Functions

Good hash function: simple uniform hashing

Assume the keys are natural numbers. If the keys are not natural numbers, we should interpret them as natural numbers.

### 3.1 The division method

$$h(k)=k\ mod\ m$$

m: a prime not too close to an exact power of 2 is often a good choice

### 3.2 The multiplication method

$$h(k)=\left \lfloor m(kA\ mod\ 1)\right \rfloor$$

m: typically a power of 2

The optimal choice of A is$$A\approx(\sqrt(5)-1)/2\approx=0.618$$

### 3.3 Universal hashing

Select a hash function randomly.

universal hash function collection: for different $$k,l \in U$$, the number of hash function $$h \in H$$ is not larger than $$\left|H\right|/m$$.

For $$h \in H$$,$$E[n_{h(k)}]$$is at most $$1+\alpha$$

A universal class of hash functions:

$$H_{pm}=\left \{h_ab:a \in Z^*_p\ and\ b \in Z_p\right \}$$

$$h_{ab}(k)=((ak+b)\ mod\ p)\ mod\ m$$

## 4. Open addressing

Open addressing avoids pointers. All the elements are stored inside the hash table.

So one key may hash to more than one slot. The hash function becomes a probe sequence.

$$\left \{h(k,0), h(k,1),…,h(k,m-1)\right \}$$

HASH-INSERT(T,k)
i=0
repeat j←h(k,i)
j=h(k,i)
if T[j]==NIL
T[j]=k
return j
else i=i+1
until i==m
error "hash table overflow"
HASH-SEARCH(T,k)
i←0
repeat j←h(k,i)
if T[j]==k
then return j
i←i+1
until T[j]=NIL or i=m
return NIL


But it is not easy to delete.

Uniform hashing: The probe sequence of each key is equally likely to be any of the $$m!$$ permutations of $$<0,1,..,m-1>$$.

Linear Probing

$$h(k,i)=(h^{‘}(k)+i)\ mod\ m,i=0,1,…,m-1$$

It has a problem known as primary clustering. The average search time increases.

Quadratic Probing

$$h(k,i)=(h^{‘}(k)+c_1i+c_2i^2)\ mod\ m$$

Secondary clustering: a milder form of clustering

Double Hashing

$$h(k,i)=(h_1(k)+ih_2(k))\ mod\ m$$

$$\alpha=n/m<1$$, expected numbers of probe in an unsuccessful search or an insert is at most $$1/{1-\alpha}$$

## 5. Perfect Hashing

If the keys are static, then the worst case time of searching can be $$O(1)$$, which is known as perfect hashing.

Perfect hashing has two levels.

The first level is same as chaining.

But the second level is a secondary hash table.

### Reference

[1] Cormen, T. H., Leiserson, C. E., Rivest, R. L., & Stein, C. (2009). Introduction to algorithms. MIT press.