A simple hash table using a vector
and a list
.
The vector contains a list of collided keys. A smart hash table will adjust it's size and rehash to minimize collisions. This is not a smart hash table.
The vector
is used as the outer container because it has much faster iteration. There is a string case for the inner container also being a vector
because list
s... they kinda suck unless you add and remove more than you iterate. I'll let the big man himself explain.
#include <iostream>
#include <vector>
#include <list>
#include <string>
#include <stdexcept>
class poor_mans_hash
{
std::vector<std::list<std::pair<int,int>>> hash_table;
int hash(int val)
{
return abs(val%static_cast<int>(hash_table.size()));
// abs because a negative number makes a very explosive vector index
}
public:
poor_mans_hash(int size): hash_table(size)
{
// all work done in member initialization list
}
void insert(int key,
int val)
{
// get list for correct element
std::list<std::pair<int,int>> &collisionlist = hash_table[hash(key)];
// see if key is in list
for (std::pair<int,int> &test: collisionlist)
{
if (key == test.first)
{
test.second = val; // update existing
return;
}
}
// key not found. Add it.
collisionlist.push_back(std::pair<int,int>(key, val));
}
bool find(int key)
{
for (std::pair<int,int> &test: hash_table[hash(key)])
{
if (key == test.first)
{
return true;
}
}
return false;
}
int & get(int key)
{
for (std::pair<int,int> &test: hash_table[hash(key)])
{
if (key == test.first)
{
// found key. Return value
return test.second;
}
}
// Not found.
throw std::out_of_range("No such key");
}
};
int main()
{
poor_mans_hash test(50);
test.insert(1, 1);
std::cout << "1: " << test.get(1) << std::endl;
try
{
std::cout << test.get(51) << std::endl;
}
catch (std::out_of_range &e)
{
std::cout << "could not get 51: " << e.what() << std::endl;
}
test.insert(11, 11);
test.insert(21, 21);
test.insert(51, 51);
std::cout << "1: " << test.get(1) << std::endl;
std::cout << "51: " << test.get(51) << std::endl;
test.insert(1, 2);
std::cout << "1: " << test.get(1) << std::endl;
}
Possible improvements to this are many. Rehashing and smarter organizing, for one thing. For another, here's a write up on all the fun things you can do to make this a good, library-like container Writing your own STL Container