Assuming \(Object1 \neq Object2\) and F(X) is a hash function
CSC 385 - Data Structures and Algorithms
University of Illinois Springfield
College of Health, Science, and Technology
A dictionary data structure associates each item with a key
This association is commonly referred to as key-value pairs
An item is retrieved by searching for its key rather than the item or some index value
The two types of hashing data structures we study are
Each behave the same way with two distinct differences
Please note that these particular implementations are for Java’s built-in types and other languages may differ
\[ F(X_{object})_{\text{hash function}} \rightarrow Y_{\text{hash code}} \]
| Key | Hash Code | Value |
|---|---|---|
| “555-0001” | \(H(key) = 1\) | “100 Elm Road” |
| “555-1214” | \(H(key) = 4\) | “150 Main Street” |
| “555-9998” | \(H(key) = 6\) | “999 Kanto Drive” |
Mapping phone number (key) to array indices which is where the value will be stored
| Index | Value |
|---|---|
| 0 | null |
| 1 | “100 Elm Road” |
| 2 | null |
| 3 | null |
| 4 | “150 Main Street” |
| 5 | null |
| 6 | “999 Kanto Drive” |
| 7 | null |
public interface HashTable<K, V> {
public boolean add(K key, V value);
public boolean remove(K key);
public V get(K key);
public boolean containsKey(K key);
public boolean containsValue(V value);
public List<K> keyList();
public List<V> valueList();
public void clear();
public int size();
public boolean isEmpty();
}Note
Perfect hash functions are not possible due to the pigeon hole principle
public int stringHashFunction(String s) {
int hashCode = 0;
for(char c : s.toCharArray()) {
hashCode += c;
}
return hashCode;
}If we call this function using the string “data structures” we get
“data structures” = 1566
The hash function in the previous slide is not a very good one
Suppose we used the same function to map the following string
“saturated crust” = 1566
We get the same exact hash code for a clearly different String
This is known as a hash collision and is something we want to make sure happens infrequently
public int stringHashFunction(String s) {
int hashCode = 0;
int position = 1;
for(char c : s.toCharArray()) {
hashCode += c * position;
position += 1;
}
return hashCode;
}Now the string “data structures” and “saturated crust” becomes
“data structures” = 12948
“saturated crust” = 12445
While not perfect, it is harder to accidentally get hash collisions
Assuming \(Object1 \neq Object2\) and F(X) is a hash function
a[k]a[k + 1], a[k + 2], etc.The cells each contain both the key and value
a[k] and a[k + 3]a[k] and a[k + 3] have a hash collisiona[k + 1] and a[k + 2] are removed by setting their corresponding locations to null
a[k + 3] due to the condition that a null was encountered at a[k + 1]k + 1, then k + 4, then k + 9| Item | Hash Code | Array Index |
|---|---|---|
| Dallas Cowboys | 137 | 137 % 13 = 7 |
| New York Giants | 358 | 358 % 13 = 7 |
| Miami Dolphins | 564 | 564 % 13 = 5 |
| Arizona Cardinals | 674 | 674 % 13 = 11 |
| Chicago Bears | 540 | 540 % 13 = 7 |
| Detroit Lions | 752 | 752 % 13 = 11 |
| Green Bay Packers | 748 | 748 % 13 = 7 |
| Index | Array |
|---|---|
| 0 | null |
| 1 | null |
| 2 | null |
| 3 | Chicago Bears |
| 4 | null |
| 5 | Miami Dolphins |
| 6 | null |
| 7 | Dallas Cowboys |
| 8 | New York Giants |
| 9 | null |
| 10 | Green Bay Packers |
| 11 | Arizona Cardinals |
| 12 | Detroit Lions |
a[k]?The first three locations in a probe sequence generated by double hashing for the search key 16
hashCode() that should be overridden by the creator of a classBoth data structures use separate chaining as their preferred collision resolution
import java.util.HashMap;
import java.util.Scanner;
public class Example {
public static void main(String args[]) {
Scanner userin = new Scanner(System.in);
String line = userin.nextLine().trim();
userin.close();
HashMap<Character, Integer> frequency = new HashMap<>();
for(char c : line.toCharArray()) {
if(frequency.containsKey(c)) {
int currentCount = frequency.get(c);
currentCount += 1;
frequency.replace(c, currentCount);
} else {
frequency.put(c, 1);
}
}
System.out.println(frequency);
}
}import java.util.HashMap;
import java.util.Scanner;
public class Example {
public static void main(String args[]) {
Scanner userin = new Scanner(System.in);
String line = userin.nextLine().trim();
userin.close();
HashMap<Character, Integer> frequency = new HashMap<>();
for(char c : line.toCharArray()) {
int currentCount = frequency.getOrDefault(c, 0);
currentCount += 1;
frequency.put(c, currentCount);
}
System.out.println(frequency);
}
}getOrDefault allows us to either get the value using the key c if it exists else return 0.
CSC 385 - Data Structures and Algorithms