Data Structure and Algorithm Design
Chapter 10
Xingang (Ian) Fang
Sections
Hashing
Map and Set ADTs
Hash Table
Hashing
Xingang (Ian) Fang
Outline
Overview
Hash functions
Applications
Overview
Use our Hash Table Collision & Load Factor Lab to compare separate chaining and linear probing, then watch the table resize.
Broad definition: Hashing is a process of mapping keys of a certain type to data of another type.
Other definition: Hashing is a process of mapping data of arbitrary size to data of fixed size. (not always true)
Hash function
The core of hashing
Representation:
<start type> -> <destination type><start type>: The type of data to be hashed, sometimes called key type<destination type>: The type of data after hashing, sometimes called hash value type or hash code typeE.g.
int -> int,int -> string,string -> int,string -> string
Hashing Glossary
- Hash Function
A function that maps a variable sized value to a fixed sized value.
- Key (hashing)
The input value to the hash function.
- Value (hashing)
A.k.a hash value, hash code or simply hash. The output of the hash function.
- Key space / Domain (hashing)
The set of all possible keys.
- Value space / Range (hashing)
The set of all possible values.
- Collision (hashing)
Multiple distinct keys maps to a same output value.
Hash Function
The function that performs the mapping
Required properties
deterministic
uniform distribution
hash function that maps all possible input values (keys) with roughly equal probability to each possible output value (hash code)
ensures minimal collision
hard to guarantee and prove
Other properties (application specific)
variable length key to fixed length hash value
constant time computation \(\Theta(1)\)
squeeze a large domain to a smaller range
chance of collision
asymmetric
Design of Hash Functions
Integer keys
String keys
Handle variable length
All characters are involved
Uniform distribution
Asymmetric hash functions
Hard to reverse
Cryptographic hash functions
E.g. MD5, SHA-1, SHA-2, SHA-3
Applications
Hash table data structure
Hash Map (Map ADT, dictionary, key-value store)
Hash Set (Set ADT)
Fingerprinting
Short summary of a large data set
Checksum
Password management
Cryptography
Advanced data structures
Bloom filter
Cuckoo filter
Merkle tree (e.g. BitCoin)
Map and Set ADTs
Try map and set operations in our ADT Explorer.
Overview
Behaviors
Overview
A map ADT is a collection of key-value pairs, where each key is unique and is used to retrieve the corresponding value.
A set ADT is a collection of unique elements, with no specific order.
Characteristics
Homogeneous
Keys in map are unique
Elements in set are unique
Finite
Dynamic size
Applications
Database indexing (map)
Caching (map)
Key-value storage (map)
Membership testing (set)
Removing duplicates from a collection (set)
Behaviors
Map Behaviors
put: Insert a key-value pair into the map.
get: Retrieve the value associated with a given key.
remove: Remove a key-value pair from the map using the key.
containsKey: Check if a key exists in the map.
Set Behaviors
add: Insert an element into the set.
remove: Remove an element from the set.
contains: Check if an element exists in the set.
Hash Table in C++
Xingang (Ian) Fang
Outline
Overview
Hash function for hash table
Collision resolution
Applications
Overview
Use our Hash Table Collision & Load Factor Lab to step through collision resolution and rehashing.
A hash table is a data structure that maps keys to values for highly efficient lookup. The key-value pairs are stored in “buckets” and the hash table maps keys to buckets using a hash function.
Requirements
Keys are unique (no duplicate keys)
Keys are immutable
Properties
Fast lookup, insert, and delete \(\Theta(1)\)
Unordered
Redundant storage to reduce collision and ensure performance
Hash Function For Hash Table
\(h(key)\) a special type of hash function used by hash table
Maps a key of an arbitrary type to an integer in a certain range \(0, 1, 2, \ldots, size - 1\), where \(size\) is the size of the hash table
The value obtained by applying the hash function to a key is called the hash value of the key. It is used as an index of the bucket.
Modulo arithmetic
Considerations
Deterministic
Fast to compute
Uniform distribution
Collision
More than one keys map to the same index
Hash Table Applications
Hash Map (key-value pairs, implementation of map ADT)
Hash Set (unique elements, implementation of set ADT)
Caching (map)
Database indexing (map)
Symbol table in compilers (map)
Counting unique elements (set)
Membership testing (set)
Deduping a collection (set)
Chaining (Collision Resolution)
Each bucket can store a variable number of key-value pairs
\(\Theta(nk)\) space complexity
where \(n\) is the number of buckets
\(k\) is the average number of key-value pairs in each bucket
Theatrically unlimited space for each bucket
\(k\) should be ideally a small constant
\(\Theta(k)\) time complexity for lookup, insert, and delete
Solve collision by chaining the key-value pairs together in one bucket when collision happens
Implementation of Chaining Hash Table
Array of Buckets (the hash table)
Fixed length
Local array
Dynamic array
Vector
Bucket
Variable length
Stores key-value pairs
Mostly empty
Linked list
Vector
Chaining Hash Table in C++
vector<vector<pair<keyType, valueType>>> hashTableVector of vectors of pair objects.
vector<LinkedListNode<keyType, valueType> *> hashTableVector of pointers to linked list.
LinkedListNode<keyType, valueType> ** hashTableOne dimensional dynamic array of pointers to a linked list.
template <typename keyType, typename valueType> struct LikedListNode { keyType key; valueType value; LinkedListNode * next; LinkedListNode * prev; };
Open Addressing (Collision Resolution)
Each bucket stores at most one key-value pair
\(\Theta(n)\) space complexity
Can store at most \(n\) key-value pairs
\(\Theta(k)\) time complexity for lookup, insert, and delete
\(k\) is the average number of probing steps
\(k\) should be ideally a small constant
Solve collision by finding another available bucket using a “probing sequence”
Implementation of Open Addressing Hash Table
Array of Buckets (the hash table)
Fixed length
Local array
Dynamic array
Vector
Bucket
Stores a key-value pair
Stores empty status and deletion status to indicate whether probing should continue.
Empty since start
Empty after deletion
Performance degradation caused by frequent delete
More “tombstone” buckets accumulate
Need rehashing to reset the hash table
Open Addressing Hash Table in C++
Bucket<keyType, valueType> * hashTableOne dimensional dynamic array of bucket objects.
vector<Bucket<keyType, valueType>> hashTableVector of bucket objects.
template <typename keyType, typename valueType> struct Bucket { keyType key; valueType value; bool isEmpty = true; bool isDeleted = false; };
Probing in Open Addressing
Find another available bucket to store the value when a collision occurs
Probing sequence: the sequence of the buckets to check when collision happens
You will never probe buckets more than \(size\) times
Linear probing:
\((h1(key) + C_{1} * i) \% size, i = 0, 1, 2, 3 \dots size - 1\)
quadratic probing:
\((h1(key) + C_{1} * i^2) \% size, i = 0, 1, 2, 3 \dots size - 1\)
double hashing probing:
\((h1(key) + C_{1} * i * h2(key)) \% size, i = 0, 1, 2, 3 \dots size - 1\)
\(h1(key)\) is the primary hash function
\(h2(key)\) is the secondary hash function
\(C_{1}\) and \(C_{2}\), etc. are constants