Separate Chaining


These notes provide more detailed pseudo-code than the pseudo-code provided by the textbook for handling a hash table implemented using separate chaining. These notes assume that each bucket in the hash table is a vector. The textbook assumes that each bucket is a list, so esssentially we are implementing the list as a vector.

Table of Contents

Data Structures

We will assume that the type of an item is a class named Data and like the textbook we will assume that the item has a field named key. Given these assumptions, here are our data structures:

// data type for an item
class Data {
    key
    other fields
}

// a bucket is a vector of items--the typedef is like a macro that defines a new
// type called bucket which is the same as vector<Data>
typedef vector<Data> bucket;

// a hash table is a vector of buckets
vector<bucket> hashTable;

Insert

Our insert function computes the bucket index for the item and then searches the bucket to ensure that the item does not already exist. If the item is already in the table, then the insert procedure should take a prescribed action such as replacing the existing item with the new item or simply aborting the insert. If the item is not already in the table, then we add the item to the end of the bucket's vector:

HashInsert(hashTable, item) {
    bucketIndex = Hash(item.key) % tablesize;
    // first search bucket to ensure key is not already in the bucket
    for i = 0 to hashTable[bucketIndex].size()-1
  	if hashTable[bucketIndex][i].key == item.key
	    // item is already in bucket. Perform a prescribed action
	    // such as replacing the item or aborting the insert. Return
	    // once the prescribed action is taken
	    return false
    // if we get to here then the item is not already in the bucket
    hashTable[bucketIndex].push_back(item)
    return true
}

Searching the Hash Table

We search the hash table by computing the bucket in which the item should reside and then performing a linear search of the bucket:

HashSearch(hashTable, key) {
    bucketIndex = Hash(key) % hashTablesize;
    for i = 0 to hashTable[bucketIndex].size()-1
	if hashTable[bucketIndex][i].key == key
	    return hashTable[bucketIndex][i]
    // if we get to here then the key was not found
    return null;
}

Deleting An Item

We delete an item from the hash table by computing the bucket in which the item should reside and then performing a linear search of the bucket to find the item. If we find the item we delete it. Normally deleting an item in the middle of a vector is inefficient because it creates a "hole" that can only be filled by moving all the entries that are to the right of the hole one entry to the left. If there are a significant number of entries to the right of the hole, then filling the hole can be very time consuming. However, we expect that on average each bucket will contain only one entry, so on average there should be very few, if any, entries that need to be shifted to the left:

HashRemove(hashTable, key) {
    bucketIndex = Hash(key) % hashTablesize;
    lastEntry = hashTable[bucketIndex].size()-1
    // find the key
    for i = 0 to lastEntry
	if hashTable[bucketIndex][i].key == key
	    delete hashTable[bucketIndex][i] 
	    return true; // no need to search further so return
    // if we get to here then the key was not found
    return false;
}