Specifications for the ADT Dictionary
Specifications for the ADT Dictionary
• Contains entries that each have two parts
p
– A key word or search key
– A value associated with the key
• The fact that every entry in a dictionary has a search key
distinguishes a dictionary from a List
A E
li h di ti
Specifications for the ADT Dictionary
Specifications for the ADT Dictionary
• Data
Data
– Pairs of objects (key, value)
Number of pairs in the collection
– Number of pairs in the collection
• Operations
•
add
•
remove
•
isEmpty
•
isFull
•
getValue
•
contains
isFull
•
getSize
Dictionary types
Dictionary types
• Distinct search Keys (Dictionary of
Distinct search Keys (Dictionary of
students, where Records organized by ID.
And ID’s are unique).
q
)
– if a key is already exists then refuse or
replace
• Duplicate search Key allowed.
• Sorted Dictionaries according to the
search key.
ADT Dictionary Interface
/** A dictionary with distinct search keys. */
import java.util.Iterator;
public interface DictionaryInterface
{{
/** Task: Adds a new entry to the dictionary. If the given search
* key already exists in the dictionary, replaces the
* corresponding value.
* @param key an object search key of the new entry
* @param value an object associated with the search key
* @return either null if the new entry was added to the dictionary
*
or the value that was associated with key if the value
or the value that was associated with key if the value
* was replaced */
public Object add(Object key, Object value);
/** T
k R
ifi
t
f
th di ti
/** Task: Removes a specific entry from the dictionary.
ADT Dictionary Interface
/** Task: Retrieves the value associated with a given search key.
* @param key an object search key of the entry to be retrieved
* @return either the value that is associated with the search key
*
ll if
h bj
t
i t */
* or null if no such object exists */
public Object getValue(Object key);
/** Task: Determines whether a specific entry is in the dictionary.
p
y
y
* @param key an object search key of the desired entry
* @return true if key is associated with an entry in the
* dictionary */
public boolean contains(Object key);
public boolean contains(Object key);
/** Task: Creates an iterator that traverses all search keys in the
* dictionary.
* @return an iterator that provides sequential access to the search
* keys in the dictionary */
ADT Dictionary Interface
/** Task: Creates an iterator that traverses all values in the
* dictionary.
* @return an iterator that provides sequential access to the
@return an iterator that provides sequential access to the
* values in the dictionary */
public Iterator getValueIterator();
/** Task: Determines whether the dictionary is empty.
* @return true if the dictionary is empty */
public boolean isEmpty();
p
p y()
/** Task: Determines whether the dictionary is full.
* @return true if the dictionary is full */
ADT Dictionary Interface
ADT Dictionary Interface
/** Task: Gets the size of the dictionary.
y
* @return the number of entries (key-value
* pairs) currently in the dictionary */
p
)
y
y
public int getSize();
/** Task: Removes all entries from the
dictionary. */
bli
id l
()
public void clear();
Applications on Dictionary ADT
Applications on Dictionary ADT
• Checking the meaning of a word
Checking the meaning of a word
• look it up in the Dictionary
• Needing an Address of somebody
• Needing an Address of somebody
• consult address book
• Needing tel Number
• Needing tel-Number
Using the ADT Dictionary
Using the ADT Dictionary
Using the ADT Dictionary
Using the ADT Dictionary
import java.io.*;
import java.util.*;
public class TelephoneDirectory
{
private DictionaryInterface phoneBook;
private static final String DELIMITERS = " \n\r\t";
p
g
public TelephoneDirectory()
{{
Using the ADT Dictionary
/** Task: Reads a text file of names and telephone numbers.
* @param dataFile a text file that is open for input */
public void readFile(BufferedReader dataFile) throws IOException
{{
String line = dataFile.readLine();
while (line != null)
{
StringTokenizer tokenizer = new StringTokenizer(line, DELIMITERS);
StringTokenizer tokenizer new StringTokenizer(line, DELIMITERS);
String firstName = (String)tokenizer.nextToken();
String lastName = (String)tokenizer.nextToken();
String phoneNumber = (String)tokenizer.nextToken();
String phoneNumber (String)tokenizer.nextToken();
Name fullName = new Name(firstName, lastName);
phoneBook.add(fullName, phoneNumber);
line = dataFile.readLine();
} // end while
Using the ADT Dictionary
Using the ADT Dictionary
public String getPhoneNumber(String firstName,
p
g g
(
g
,
String lastName)
{
Name fullName = new Name(firstName,
lastName);
Using the ADT Dictionary
Using the ADT Dictionary
public static void main(String[] args)
{{
TelephoneDirectory directory = new TelephoneDirectory();
String fileName = "data.txt";
try
try
{
FileReader reader = new FileReader(fileName);
BufferedReader dataFile = new BufferedReader(reader);
directory.readFile(dataFile);
} // end try
catch (IOException e)
catch (IOException e)
{
iterators
iterators
getKeyIterator
and
getValueIterator
return iterators
Example:
Iterator keyIterator=myTable.getKeyIterator();
Java Class Library: The Interface
Map
Java Class Library: The Interface
Map
• A list of method signatures in Map
A list of method signatures in Map
– Note similarity to methods developed in our
ADT
ADT
public
Object put(Object key, Object value);
public
Object remove(Object key);
public
Object get(Object key);
p
j
g (
j
y);
public boolean
containsKey(Object key);
public boolean
containsValue(Object value);
public
Set keySet();
public
Collection values();
public
Collection values();
public boolean
isEmpty();
public int
size();
Array Based Implementations
• Each entry consists of two parts
– A search key
– A value
• Strategies
– Encapsulate the two parts into an object
j
– Use two parallel arrays
Array Based Implementations
Array Based Implementations
3 ways to use arrays
y
y
to represent
dictionary entries:
( )
f
t
(a) an array of entry
objects;
(b) parallel arrays of
(b) parallel arrays of
search keys and
values;
The Entries
The Entries
• A class to represent the two-part entries
i t l E t i l t
private class Entry implements
{ private Object key;
private Object value;
i t E t (Obj t hK Obj t d t V l )
private Entry(Object searchKey, Object dataValue) { key = searchKey;
value = dataValue; } // end constructor
i t Obj t tK ()
private Object getKey()
{ return key; } // end getKey
private Object getValue()}
{ return value; } // end getValue
private void setValue(Object dataValue)
Unsorted Array-Based Dictionary
Unsorted Array Based Dictionary
• Unsorted array-
Unsorted, array
based dictionary:
• (a) adding an
• (a) adding an
entry;
(b)
i
Sorted Array-Based Dictionary
Sorted Array Based Dictionary
Adding an entry to
Adding an entry to
a sorted
array-based dictionary:
based dictionary:
(a) search;
Array-Based Implementations
Array Based Implementations
• Unsorted worst-case efficiencies
– Addition O(1)
– Removal O(n)
– Retrieval O(n)
– Traversal O(n)
• Sorted worst case efficiencies
• Sorted worst-case efficiencies
– Addition O(n)
– Removal O(n)
( )
Sorted Array-Based Dictionary
Sorted Array Based Dictionary
•
Beginning of the class
public class
SortedArrayDictionary
implements
DictionaryInterface,
{
private
Entry [] entries;
// array of sorted entries
private int
currentSize = 0; // number of entries
private int
currentSize 0; // number of entries
private final static int
DEFAULT_MAX_SIZE = 25;
public
SortedArrayDictionary()
{
entries =
new
Entry[DEFAULT_MAX_SIZE];
currentSize = 0;
currentSize 0;
} // end default constructor
public
SortedArrayDictionary(
int
maxSize)
{
entries =
new
Entry[maxSize];
Sorted Array-Based Dictionary
public Object add(Object key, Object value)
{
Object result = null;
i t k I d l t I d (k ) int keyIndex = locateIndex(key); if ( (keyIndex < currentSize)
&& key.equals(entries[keyIndex].getKey()) ) {{
// key found; return and replace old value result = entries[keyIndex].getValue(); entries[keyIndex].setValue(value); } else else { if (isArrayFull())
doubleArray(); // expand array makeRoom(keyIndex);
entries[keyIndex] = new Entry(key, value); currentSize++;
Sorted Array-Based Dictionary
Sorted Array Based Dictionary
private int locateIndex(Object key)
{
// sequential search
Comparable cKey = (Comparable) key;
int index = 0;
while ( (index < currentSize) &&
( (
)
cKey.compareTo(entries[index].getKey()) > 0 )
index++;
return index;
Vector-Based Implementations
Vector Based Implementations
• Similar in spirit to the array-based version
Similar in spirit to the array based version
• With vector no need for …
makeRoom
–
makeRoom
–
doubleArray
–
isArrayFull
isArrayFull
– Counting entries, vector does so for you
• Downside
• Downside
Vector-Based Implementations
Vector Based Implementations
• Beginning of the class
g
g
public class
SortedVectorDictionary
implements
DictionaryInterface,
{
private
Vector entries;
public
SortedVectorDictionary()
{entries =
new
Vector();
//
{entries =
new
Vector();
// as needed, vector doubles its size
} // end default constructor
public
SortedVectorDictionary(
int
maxSize)
{
entries
new
Vector(maxSize);
{
entries =
new
Vector(maxSize);
Vector-Based Implementations
public Object add(Object key, Object value)
{
Object result = null;
int keyIndex = locateIndex(key);
int keyIndex locateIndex(key);
if ( (keyIndex < entries.size()) &&
key.equals(((Entry)entries.elementAt(keyIndex)).getKey()))
{{
// key found; return and replace old value
Entry currentEntry = (Entry) entries.elementAt(keyIndex);
result = currentEntry.getValue();
currentEntry.setValue(value);
currentEntry.setValue(value);
}
else // add new entry
{
Entry newEntry = new Entry(key, value);
Entry newEntry new Entry(key, value);
entries.insertElementAt(newEntry, keyIndex);
} // end if
Linked Implementations
Linked Implementations
Linked Implementations
Linked Implementations
Linked Implementations
Linked Implementations
Linked Implementations
Linked Implementations
Linked Implementations
Linked Implementations
• Unsorted worst-case efficiencies
– Addition O(1)
– Removal O(n)
– Retrieval O(n)
– Traversal O(n)
• Sorted worst case efficiencies
• Sorted worst-case efficiencies
Linked Implementations
public class SortedLinkedDictionary implements DictionaryInterface { private int currentSize; // number of entries
private Node firstNode; // reference to first node of chain public SortedLinkedDictionary()
{{
firstNode = null; currentSize = 0;
} // end default constructor
public Object add(Object key, Object value) {
Object result = null;
Node newNode = new Node(key, value); // create new node Node newNode new Node(key, value); // create new node Node currentNode = firstNode;
Node nodeBefore = null;
C bl K (C bl ) k Comparable cKey = (Comparable) key;
Linked Implementations
while ( (currentNode != null) && cKey compareTo(currentNode getKey()) > 0 ) while ( (currentNode ! null) && cKey.compareTo(currentNode.getKey()) > 0 )
{
nodeBefore = currentNode;
currentNode = currentNode.getNextNode(); } // end while
if ( (currentNode != null) && key.equals(currentNode.getKey()) ) {
result = currentNode.getKey();
currentNode.setValue(value); // replace value( ); p }
// should insertion be at beginning of chain? else if (isEmpty() || (nodeBefore == null)) {
newNode setNextNode(firstNode); newNode.setNextNode(firstNode); firstNode = newNode;
currentSize++; }
else // add elsewhere in non-empty list {
Hashing as a Dictionary Implementation
Hashing as a Dictionary Implementation
• What is Hashing?
g
• A technique that determines an index or location
for storage of an item in a data structure
• The hash function receives the search key
– Returns the index of an element in an array called the
hash table
hash table
– The index is known as the hash index
What is Hashing?
What is Hashing?
• Two steps of the hash function
Two steps of the hash function
– Convert the search key into an integer called
the hash code
the hash code
– Compress the hash code into the range of
indices for the hash table
indices for the hash table
• Typical hash functions are not perfect
They can allow more than one search key to
– They can allow more than one search key to
map into a single index
What is Hashing?
What is Hashing?
Let TableSize= 100
Let TableSize 100
Hash Functions
Hash Functions
• General characteristics of a good hash
General characteristics of a good hash
function
Minimize collisions
– Minimize collisions
– Distribute entries uniformly throughout the
hash table
hash table
Computing Hash Codes
Computing Hash Codes
• The hash code for a string,
s
int
hash = 0;
int
n = s.length();
for
(
(
int
i = 0; i < n; i++)
;
;
)
hash = g * hash + s.charAt(i); // g is a positive
constant
• Hash code for a primitive type
p
yp
– Use the primitive typed key itself (casting to int)
– Manipulate internal binary representations (ignore part of internal
binary representation )
U
f ldi
– Use folding
1) Divining a primitive data type into several pieces
2) Combination of pieces by using addition or
Computing Hash Codes
Computing Hash Codes
• Example: Folding
Example: Folding
(int) key ^ (key>> 32)
• Key>> 32 shifting a 64-bit key to the right
Key>> 32 shifting a 64 bit key to the right
by 32 bits (the right half will be eliminated)
• ^ is exclusive or
is exclusive or
• For a 8-bit binary number:
1) 10101100 >> 4 = 00001010
1) 10101100 >> 4 00001010
2) 10101100 ^ 00001010= 10100110
Compressing a Hash Code
Compressing a Hash Code
• Must compress the hash code so it fits into the index
p
range
• Typical method for a code
c
is to compute
c
modulo
n
–
n
n
is a prime number (the size of the table)
is a prime number (the size of the table)
– Index will then be between 0 and
n – 1
private int
getHashIndex(Object key)
{
int
hashIndex = key.hashCode() %
hashTable.length;
if
(hashIndex < 0)
hashIndex = hashIndex + hashTable.length;
return
hashIndex;
Open Addressing with Linear Probing
Open Addressing with Linear Probing
• Open addressing
Open addressing
scheme locates alternate
location
– New location must be
open, available
• Linear probing
– If collision occurs at
h
hT bl [k] l
k
hashTable[k], look
successively at location
k + 1 k + 2
Open Addressing, Quadratic Probing
Open Addressing, Quadratic Probing
• Change the probe sequence
Change the probe sequence
– Given search key k
Probe to
k + 1 k + 2
2
k + 3
2
k + n
2
– Probe to k + 1, k + 2
2
, k + 3
2
, … k + n
2
• Reaches every location in the hash table if
t bl
i
i
i
b
Open Addressing with Double Hashing
Open Addressing with Double Hashing
• Resolves collision by examining locations
Resolves collision by examining locations
– At original hash index
– Plus an increment determined by 2
Plus an increment determined by 2
nd
function
function
• Second hash function
– Different from first
Different from first
– Depends on search key
– Returns nonzero value
Example of double hashing
Example of double hashing
•
h1( key)= key % 7
(
y)
y
h2
(
key)= 5- (key % 5)
•
h1( 16)= 16%7= 2
•
h2( 16)= 5- (16%5)= 5-1=4
•
The probe sequence start at 2 and probes locations
increment of 4
increment of 4
Example of double hashing
Example of double hashing
Separate Chaining
Separate Chaining
• Alter the structure of the hash table
Alter the structure of the hash table
• Each location can represent multiple values
– Each location called a bucket
Each location called a bucket
• Bucket can be a(n)
– List
– Sorted list
– Chain of linked nodes
– Array
Separate Chaining
Separate Chaining
Separate Chaining
Separate Chaining
A Dictionary Implementation That Uses Hashing
A Dictionary Implementation That Uses Hashing
• Beginning of private class
Beginning of private class
TableEntry
TableEntry
– Made internal to dictionary class
private clas
s TableEntry {
private
Object entryKey;
p
j
y
y;
private
Object entryValue;
private boolean
inTable;
// true if entry is in hash table
private
TableEntry(Object key, Object value)
{
entryKey = key;
{
entryKey = key;
entryValue = value;
inTable =
true
;
A Dictionary Implementation That Uses Hashing
public class HashedMapOpenAddressing implements DictionaryInterface,
j
i S i li
bl
java.io.Serializable
{
private TableEntry[] hashTable; // dictionary entries
private int currentSize; // current number of entries
p
;
private static final int DEFAULT_SIZE = 101; // must be prime
// fraction of hash table that can be filled
private static final double MAX LOAD FACTOR = 0 5;
private static final double MAX_LOAD_FACTOR = 0.5;
public HashedMapOpenAddressing()
{
hashTable = new TableEntry[DEFAULT_SIZE];
currentSize = 0;
A Dictionary Implementation That Uses
H
hi
Hashing
public HashedMapOpenAddressing(int
public HashedMapOpenAddressing(int
tableSize)
{{
int primeSize = getNextPrime(tableSize);
hashTable = new TableEntry[primeSize];
hashTable new TableEntry[primeSize];
currentSize = 0;
A Dictionary Implementation That Uses
H
hi
Hashing
public Object getValue(Object key)
{{
Object result = null;
int index = getHashIndex(key);
int index = getHashIndex(key);
index = locate(index, key);
if (index != -1)
if (index ! 1)
result = hashTable[index].getValue(); // key found; get value
// else key not found; result is null
y
;
A Dictionary Implementation That Uses
H
hi
Hashing
public Object remove(Object key)
{{
Object result = null;
int index = getHashIndex(key);
index = locate(index key);
index = locate(index, key);
if (index != -1)
{ // key found; flag entry as removed and return its value
hashTable[index] setToRemoved();
hashTable[index].setToRemoved();
result = hashTable[index].getValue();
currentSize--;
} // end if
// else key not found; result is null
// else key not found; result is null
A Dictionary Implementation That Uses Hashing
private int locate(int index, Object key) {
boolean found = false;
boolean repeatedIndex = false;
int firstIndex = index; // first index in probe sequence int firstIndex = index; // first index in probe sequence
while ( !found && !repeatedIndex && (hashTable[index] != null) ) {
if ( hashTable[index].isIn() && key.equals(hashTable[index].getKey()) ) found = true; // key found
else // follow probe sequence
index = (index + 1) % hashTable.length; // linear probing if (index == firstIndex)
if (index firstIndex)
repeatedIndex = true; // probe sequence is repeating } // end while
// Assertion: either key is found or a null location is reached i t lt 1
int result = -1; if (found)
A Dictionary Implementation That Uses Hashing
private int getHashIndex(Object key)
p
g
(
j
y)
{
int hashIndex = key.hashCode() %
y
()
hashTable.length;
if (hashIndex < 0)
hashIndex = hashIndex + hashTable.length;
h
hI d
A Dictionary Implementation That Uses Hashing
public Object add(Object key, Object value)
{
Object oldValue; // value to return if (isHashTableTooFull())
rehash();
int index = getHashIndex(key);
index = probe(index, key); // check for and resolve collision // Assertion: index is within legal range for hashTable
if ( (hashTable[index] == null) || hashTable[index].isRemoved()) { // key not found, so insert new entry
{ // key not found, so insert new entry
hashTable[index] = new TableEntry(key, value); currentSize++;
oldValue = null; }
l else
{ // key found; get old value for return and then replace it oldValue = hashTable[index].getValue();
hashTable[index].setValue(value); } // end if
A Dictionary Implementation That Uses Hashing
private int probe(int index, Object key){
boolean found = false;
boolean repeatedIndex = false;
int firstIndex = index; // first index in probe sequence i t dSt t I d 1 // i d f fi t l ti i int removedStateIndex = -1; // index of first location in
// removed state
while ( !found && !repeatedIndex && (hashTable[index] != null) ) {
if (hashTable[index].isRemoved()) {{
// save index of first not-in-use location found if (removedStateIndex == -1)
removedStateIndex = index;
index = (index + 1) % hashTable.length; // linear probing }
else if (key.equals(hashTable[index].getKey())) found = true; // key found
else // follow probe sequence
index = (index + 1) % hashTable.length; // linear probing
if (i d fi tI d ) if (index == firstIndex)
repeatedIndex = true; // probe sequence is repeating } // end while
// Assertion: either key or null is found at hashTable[index]
A Dictionary Implementation That Uses
H
hi
Hashing
private void rehash()
{{
TableEntry[] oldTable = hashTable;
int oldSize = hashTable.length;
int newSize = getNextPrime(oldSize + oldSize);
hashTable = new TableEntry[newSize]; // increase size of array
hashTable = new TableEntry[newSize]; // increase size of array
currentSize = 0; // reset size of dictionary, since it will be
// incremented by add during rehash
// rehash dictionary entries from old array to the new and bigger
// rehash dictionary entries from old array to the new and bigger
// array; skip both null locations and removed entries
for (int index = 0; index < oldSize; index++)
{
if ( (oldTable[index] != null) && oldTable[index] isIn() )
if ( (oldTable[index] != null) && oldTable[index].isIn() )
add(oldTable[index].getKey(), oldTable[index].getValue());
} // end for