#ifndef HashKey_h
#define HashKey_h
#include <stdint.h>
template<typename K>
class HashKey {
public:
static uint16_t gethash(K key) {
// designed to hash non-numeric keys
uint16_t hash = 5381;
uint8_t* b = (uint8_t*)&key;
for (int i = 0, j = sizeof(K); i < j; i++) {
hash = ((hash << 5) + hash) + b[i];
}
return hash;
}
};
template<>
class HashKey<uint16_t> {
public:
static uint16_t gethash(uint16_t key) {
return key;
}
};
template<>
class HashKey<int16_t> {
public:
static uint16_t gethash(int16_t key) {
return key;
}
};
template<>
class HashKey<uint8_t> {
public:
static uint16_t gethash(uint8_t key) {
return key;
}
};
template<>
class HashKey<int8_t> {
public:
static uint16_t gethash(int8_t key) {
return key;
}
};
template<>
class HashKey<int32_t> {
public:
static uint16_t gethash(int32_t key) {
return key;
}
};
template<>
class HashKey<uint32_t> {
public:
static uint16_t gethash(uint32_t key) {
return key;
}
};
#endif
#ifndef Pair_h
#define Pair_h
template <class T1, class T2>
struct pair {
T1 first;
T2 second;
pair() : first(T1()), second(T2()) {}
pair(const T1& a, const T2& b) : first(a), second(b) {}
};
template <class T1, class T2>
inline pair<T1, T2> make_pair(const T1& k, const T2& t)
{
return pair<T1, T2>(k, t);
}
#endif
#ifndef HashTableLP_h
#define HashTableLP_h
#include "HashKey.h"
#include "Pair.h"
template<typename T, typename K>
class HashTableLP {
public:
class HashEntry;
class iterator;
HashTableLP(size_t);
HashTableLP(size_t, uint16_t);
~HashTableLP();
void insert(K, T);
void insert(K, T, uint16_t);
iterator begin();
T* find(K);
T* find(K, uint16_t);
size_t count();
void erase(K);
void erase(K, uint16_t);
void clear();
protected:
HashEntry **table;
const HashEntry* DELETED = (HashEntry*)1;
size_t tSize;
private:
uint16_t getPrime(size_t);
void initTable(size_t, uint16_t);
uint16_t moduloValue;
uint16_t primes[10] =
{ 19, 31, 47, 59, 61, 97, 127, 251, 509, 1021 };
};
template<typename T, typename K>
class HashTableLP<T, K>::HashEntry {
public:
HashEntry(K key, T data) {
this->key = key;
this->data = data;
}
K key;
T data;
};
template<typename T, typename K>
class HashTableLP<T, K>::iterator : public pair<K, T> {
public:
iterator(HashTableLP* p) {
parent = p;
nxtIdx = -1;
noMore = false;
setNext();
}
bool hasNext() {
return !noMore;
}
iterator &operator ++(int) {
setNext();
return *this;
}
iterator &operator ++() {
setNext();
return *this;
}
private:
size_t nxtIdx;
HashTableLP* parent;
bool noMore;
void setNext() {
nxtIdx++;
for (; nxtIdx <= parent->tSize; nxtIdx++) {
if (nxtIdx < parent->tSize && (parent->table[nxtIdx] && parent->table[nxtIdx] != parent->DELETED)) {
break;
}
}
if (nxtIdx < parent->tSize) {
setPair(nxtIdx);
}
else {
noMore = true;
}
}
void setPair(size_t idx) {
this->first = parent->table[idx]->key;
this->second = parent->table[idx]->data;
}
};
// constructors and destructor
template<typename T, typename K>
HashTableLP<T, K>::HashTableLP(size_t tableSize) {
int top = sizeof(primes) / sizeof(uint16_t) - 1;
uint16_t modulo = primes[top];
if (tableSize <= modulo) {
while (top > 0 && tableSize < modulo) {
modulo = primes[--top];
}
}
else {
modulo = getPrime(tableSize);
}
initTable(tableSize, modulo);
}
template<typename T, typename K>
HashTableLP<T, K>::HashTableLP(size_t tableSize, uint16_t modulo) {
initTable(tableSize, modulo);
}
template<typename T, typename K>
HashTableLP<T, K>::~HashTableLP() {
for (int i = 0; i < tSize; i++) {
if (table[i] && table[i] != DELETED) {
free(table[i]);
//delete table[i]; in most instances
}
}
free(table);
//delete[] table; would be normal
}
// public methods
template<typename T, typename K>
void HashTableLP<T, K>::insert(K key, T data) {
// no key hash supplied
insert(key, data, HashKey<K>::gethash(key)); // call the overloaded version
}
template<typename T, typename K>
void HashTableLP<T, K>::insert(K key, T data, uint16_t hash) {
hash %= moduloValue;
int deletedSlot = -1;
uint16_t saveHash = hash;
while (table[hash] == DELETED || (table[hash] && table[hash]->key != key)) {
if (table[hash] == DELETED) {
// passed a delete slot
deletedSlot = hash; // save it as usable slot
}
hash = ++hash % moduloValue;
if (hash == saveHash) {
// if the table is full of values and deleted slots
// then we want to stop looking for a duplicate key and
// just use a deleted slot
if (deletedSlot > -1) {
goto BeenAround;
}
else {
return; // no accessible slot left in the table
}
}
}
if (table[hash]) {
delete table[hash];
deletedSlot = -1; // not required
}
BeenAround:
if (deletedSlot > -1) {
table[deletedSlot] = new HashEntry(key, data);
}
else {
table[hash] = new HashEntry(key, data);
}
}
template<typename T, typename K>
T* HashTableLP<T, K>::find(K key) {
return find(key, HashKey<K>::gethash(key));
}
template<typename T, typename K>
T* HashTableLP<T, K>::find(K key, uint16_t hash) {
hash %= moduloValue;
while (table[hash] == DELETED || (table[hash] && table[hash]->key != key)) {
hash = ++hash % moduloValue;
}
if (table[hash]) {
return &table[hash]->data;
}
return NULL;
}
template<typename T, typename K>
void HashTableLP<T, K>::erase(K key) {
erase(key, HashKey<K>::gethash(key));
}
template<typename T, typename K>
void HashTableLP<T, K>::erase(K key, uint16_t hash) {
hash %= moduloValue;
while (table[hash] == DELETED || (table[hash] && table[hash]->key != key)) {
hash = ++hash % moduloValue;
}
if (table[hash]) {
delete table[hash];
table[hash] = (HashEntry*)DELETED;
}
}
template<typename T, typename K>
size_t HashTableLP<T, K>::count() {
size_t ctr = 0;
for (int i = 0; i < tSize; i++) {
if (table[i] && table[i] != DELETED) {
ctr++;
}
}
return ctr;
}
template<typename T, typename K>
typename HashTableLP<T, K>::iterator HashTableLP<T, K>::begin() {
iterator it(this);
return it;
}
template<typename T, typename K>
void HashTableLP<T, K>::clear() {
for (int i = 0; i < tSize; i++) {
if (table[i]) {
if (table[i] != DELETED) {
delete table[i];
}
table[i] = NULL;
}
}
}
// private methods
template<typename T, typename K>
void HashTableLP<T, K>::initTable(size_t tableSize, uint16_t modulo) {
tSize = tableSize;
table = new HashEntry*[tSize];
for (int i = 0; i < tSize; i++) {
table[i] = NULL;
}
moduloValue = modulo;
}
template<typename T, typename K>
uint16_t HashTableLP<T, K>::getPrime(size_t num) {
// returns the largest prime <= num
if (num % 2 == 0) { num--; }
for (uint16_t p = num; p > 2; p -= 2) {
bool f = false;
for (int i = 2; i < p / 2; i++) {
if (p % i == 0) {
f = true;
break;
}
}
if (!f) {
return p;
}
}
return num; // best we can do
}
#endif
#include "stdafx.h"
#include <stdint.h>
#include <stdlib.h>
#include "HashTableLP.h"
#include <iostream>
//using namespace std;
int32_t getIsbn(char*);
uint16_t hashISBN(char*);
void test1();
void test2();
void test3();
char TPBooks[][2][32] = { { "The shepherd's crown", "9780857534811" },
{ "Raising steam", "9780857522276" },
{ "Snuff", "9780385619264" },
{ "I shall wear midnight", "9780552555593" },
{ "Unseen academicals", "9780385609340" },
{ "Making money", "9780385611015" },
{ "Thud!", "9780552152679" },
{ "Going postal", "9780552149433" },
{ "Monstrous Regiment", "9780552154314" },
{ "Night watch", "9780552148993" },
{ "Thief of time", "9780552154260" } };
struct tpBook {
char title[32];
// maybe some other data
} book;
struct tpIsbn {
char isbn[14];
// we need a != operator
bool operator!=(tpIsbn& i) {
char *a = &isbn[0], *b = &i.isbn[0];
for (; *a == *b; a++, b++) {
if (*a == '\0' || *b == '\0') {
if (*a == *b) { return false; }
break; // end of one string
}
}
return true;
}
} key;
int main()
{
test1();
std::cout << "End of Test 1\n";
std::cin.get();
test2();
std::cout << "End of Test 2\n";
test3();
std::cout << "End of Test 3\n";
std::cin.get();
return 0;
}
void test1() {
HashTableLP<tpBook, tpIsbn> hashLP(20);
for (int i = 0; i < 11; i++) {
strcpy(book.title, TPBooks[i][0]);
strcpy(key.isbn, TPBooks[i][1]);
hashLP.insert(key, book, hashISBN(key.isbn));
//hashLP.insert(key, book);
}
std::cout << hashLP.count() << " items inserted\n";
for (HashTableLP<tpBook, tpIsbn>::iterator it = hashLP.begin(); it.hasNext(); it++) {
std::cout << it.first.isbn << " " << it.second.title << '\n';
}
tpBook* found = hashLP.find(key, hashISBN(key.isbn));
//tpBook* found = hashLP.find(key);
if (found) {
std::cout << "Found: " << found->title << '\n';
}
else {
std::cout << "Not Found\n";
}
}
void test2() {
HashTableLP<tpBook, int32_t> newLP(20);
for (int i = 0; i < 11; i++) {
strcpy(book.title, TPBooks[i][0]);
strcpy(key.isbn, TPBooks[i][1]);
newLP.insert(getIsbn(key.isbn), book);
}
std::cout << newLP.count() << " items inserted\n";
for (HashTableLP<tpBook, int32_t>::iterator it = newLP.begin(); it.hasNext(); it++) {
std::cout << it.first << " " << it.second.title << '\n';
}
}
void test3() {
std::cout << "In Test 3\n";
HashTableLP<int, int> hashLP(128);
for (int i = 0; i < 120; i++) {
hashLP.insert(i, i, i); // should get average 3 per slot
}
std::cout << hashLP.count() << " items inserted\n";
for (int i = 80; i < 99; i++) {
hashLP.erase(i, i);
}
std::cout << hashLP.count() << " items remaining\n";
hashLP.insert(98, 256, 98);
for (int i = 80; i < 99; i++) {
hashLP.insert(i, i, i); // put em back
}
std::cout << hashLP.count() << " items now\n";
hashLP.insert(80, 256, 80);
for (HashTableLP<int, int>::iterator it = hashLP.begin(); it.hasNext(); it++) {
std::cout << it.first << " " << it.second << '\n';
}
}
int32_t getIsbn(char *isbn) {
char subStr[9];
subStr[8] = '\0';
// drop leading 4 chars and final check digit
isbn += 4;
strncpy(subStr, isbn, 8);
return atol(subStr);
}
uint16_t hashISBN(char *isbn) {
char subStr[9];
subStr[8] = '\0';
// drop leading 4 chars and final check digit
isbn += 4;
strncpy(subStr, isbn, 8);
return (uint16_t)atol(subStr);
}
#include "HashTableLP.h"
//#include "HashTableSC.h"
template<class T> inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; }
const char TPBooks[][2][32] = {{"The shepherd's crown", "9780857534811"},
{"Raising steam", "9780857522276"},
{"Snuff", "9780385619264"},
{"I shall wear midnight", "9780552555593"},
{"Unseen academicals", "9780385609340"},
{"Making money", "9780385611015"},
{"Thud!", "9780552152679"},
{"Going postal", "9780552149433"},
{"Monstrous Regiment", "9780552154314"},
{"Night watch", "9780552148993"},
{"Thief of time", "9780552154260"}};
struct tpBook{
char title[32];
// maybe some other data
} book;
struct tpIsbn{
char isbn[14];
// we need a != operator
bool operator!=(const tpIsbn& i) {
char *a = &isbn[0], *b = &i.isbn[0];
for(; *a == *b; a++, b++) {
if(*a == '\0' || *b == '\0') {
if(*a == *b) { return false;}
break; // end of one string
}
}
return true;
}
} key;
void setup() {
Serial.begin(115200);
HashTableLP<tpBook, tpIsbn> hashSC(10);
for (int i = 0; i < 1; i++) {
strcpy_P(book.title, TPBooks[i][0]);
strcpy_P(key.isbn,TPBooks[i][1]);
hashSC.insert(key, book, hashISBN(key.isbn));
Serial << "Inserted\n";
}
Serial << hashSC.count() << " items inserted\n";
for(HashTableLP<tpBook, tpIsbn>::iterator it = hashSC.begin(); it.hasNext(); it++) {
Serial << it.first.isbn << " " << it.second.title << '\n';
}
tpBook* found = hashSC.find(key, hashISBN(key.isbn));
//tpBook* found = hashLP.find(key);
if(found) {
Serial << "Found: " << found->title << '\n';
} else {
Serial << "Not Found\n";
}
hashSC.erase(key, hashISBN(key.isbn));
Serial << hashSC.count() << " items remaining\n";
for(HashTableLP<tpBook, tpIsbn>::iterator it = hashSC.begin(); it.hasNext(); it++) {
Serial << it.first.isbn << " " << it.second.title << '\n';
}
hashSC.~HashTableLP();
}
int32_t getIsbn(char *isbn) {
char subStr[9];
subStr[8] = '\0';
// drop leading 4 chars and final check digit
isbn +=4;
strncpy(subStr, isbn, 8);
return atol(subStr);
}
uint16_t hashISBN(char *isbn){
char subStr[9];
subStr[8] = '\0';
// drop leading 4 chars and final check digit
isbn +=4;
strncpy(subStr, isbn, 8);
return (uint16_t)atol(subStr);
}
#ifndef HashTableSC_h
#define HashTableSC_h
#include "Pair.h"
template<typename T, typename K>
class HashTableSC {
public:
class HashEntry;
class iterator;
HashTableSC(size_t);
HashTableSC(size_t, uint16_t);
~HashTableSC();
void insert(K, T, uint16_t);
iterator begin();
T* find(K, uint16_t);
size_t count();
void erase(K, uint16_t);
void clear();
protected:
HashEntry **table;
size_t tSize;
private:
uint16_t getPrime(size_t);
void initTable(size_t, uint16_t);
uint16_t moduloValue;
uint16_t primes[12] =
{ 7, 13, 19, 31, 47, 59, 61, 97, 127, 251, 509, 1021 };
};
template<typename T, typename K>
class HashTableSC<T, K>::HashEntry {
public:
HashEntry(K key, T data) {
this->key = key;
this->data = data;
next = NULL;
}
K key;
T data;
HashEntry* next;
};
template<typename T, typename K>
class HashTableSC<T, K>::iterator : public pair<K, T> {
public:
iterator(HashTableSC* p) {
parent = p;
nxtIdx = -1;
noMore = false;
currentEntry = NULL;
setNext();
}
bool hasNext() {
return !noMore;
}
iterator &operator++() {
setNext();
return *this;
}
iterator &operator++(int) {
setNext();
return *this;
}
private:
size_t nxtIdx;
HashTableSC* parent;
HashEntry* currentEntry;
bool noMore;
void setNext() {
// needs MOD to check if current entry has a forward link
if (currentEntry && currentEntry->next) {
currentEntry = currentEntry->next;
}
else {
nxtIdx++;
for (; nxtIdx <= parent->tSize; nxtIdx++) {
if (nxtIdx < parent->tSize && parent->table[nxtIdx]) {
break;
}
}
if (nxtIdx < parent->tSize) {
currentEntry = parent->table[nxtIdx];
}
else {
noMore = true;
currentEntry = NULL;
}
}
if (currentEntry) {
setPair(currentEntry);
}
}
void setPair(HashEntry* p) {
this->first = p->key;
this->second = p->data;
}
};
// constructors and destructor
template<typename T, typename K>
HashTableSC<T, K>::HashTableSC(size_t tableSize) {
int top = sizeof(primes) / sizeof(uint16_t) - 1;
uint16_t modulo = primes[top];
if (tableSize <= modulo) {
while (top > 0 && tableSize < modulo) {
modulo = primes[--top];
}
}
else {
modulo = getPrime(tableSize);
}
initTable(tableSize, modulo);
}
template<typename T, typename K>
HashTableSC<T, K>::HashTableSC(size_t tableSize, uint16_t modulo) {
initTable(tableSize, modulo);
}
template<typename T, typename K>
HashTableSC<T, K>::~HashTableSC() {
for (int i = 0; i < tSize; i++) {
if (table[i]) {
if (table[i]->next) {
HashEntry* h = table[i];
HashEntry* n = h->next;
while (n) {
free(h);
h = n;
n = n->next;
}
}
else {
free(table[i]);
//delete table[i]; in most instances
}
}
}
free(table);
//delete[] table; would be normal
}
// public Methods
template<typename T, typename K>
void HashTableSC<T, K>::insert(K key, T data, uint16_t hash) {
hash %= moduloValue;
if (table[hash]) {
// slot taken but might be an update
if (table[hash]->key != key) {
// chain the new entry
HashEntry* h = table[hash];
while (h->next) {
h = h->next;
}
h->next = new HashEntry(key, data); // fill slot with entry
}
else {
free(table[hash]);
table[hash] = new HashEntry(key, data);
}
}
else {
table[hash] = new HashEntry(key, data);
}
}
template<typename T, typename K>
T* HashTableSC<T, K>::find(K key, uint16_t hash) {
hash %= moduloValue;
if (table[hash]) {
// an entry in the hash slot but is it the key we want?
HashEntry* h = table[hash];
while (h && h->key != key) {
h = h->next;
}
if (h) {
return &h->data;
}
}
return NULL;
}
template<typename T, typename K>
void HashTableSC<T, K>::erase(K key, uint16_t hash) {
hash %= moduloValue;
if (table[hash]) {
HashEntry* h = table[hash];
if (h->key != key) {
HashEntry* n = NULL;
while (h && h->key != key) {
n = h;
h = h->next;
}
n->next = h->next; // NULL or next in the chain
}
else {
if (h->next) {
table[hash] = h->next;
}
else {
table[hash] = NULL;
}
}
if (h) {
free(h);
// delete h;
}
}
}
template<typename T, typename K>
size_t HashTableSC<T, K>::count() {
size_t ctr = 0;
for (int i = 0; i < tSize; i++) {
if (table[i]) {
ctr++;
HashEntry* h = table[i];
while (h->next) {
ctr++;
h = h->next;
}
}
}
return ctr;
}
template<typename T, typename K>
typename HashTableSC<T, K>::iterator HashTableSC<T, K>::begin() {
iterator it(this);
return it;
}
template<typename T, typename K>
void HashTableSC<T, K>::clear() {
for (int i = 0; i < tSize; i++) {
if (table[i]) {
if (table[i]->next) {
HashEntry* h = table[i];
HashEntry* n = h->next;
while (n) {
free(h);
h = n;
n = n->next;
}
}
else {
free(table[i]);
// delete table[i]; or delete
}
table[i] = NULL;
}
}
}
// Private methods
template<typename T, typename K>
void HashTableSC<T, K>::initTable(size_t tableSize, uint16_t modulo) {
tSize = tableSize;
table = new HashEntry*[tSize];
for (int i = 0; i < tSize; i++) {
table[i] = NULL;
}
moduloValue = modulo;
}
template<typename T, typename K>
uint16_t HashTableSC<T, K>::getPrime(size_t num) {
// returns the largest prime <= num
if (num % 2 == 0) { num--; }
for (uint16_t p = num; p > 2; p -= 2) {
bool f = false;
for (int i = 2; i < p / 2; i++) {
if (p % i == 0) {
f = true;
break;
}
}
if (!f) {
return p;
}
}
return num; // best we can do as num must be strange
}
#endif
#include "stdafx.h"
#include <stdint.h>
#include <stdlib.h>
#include "HashTableSC.h"
#include <iostream>
//using namespace std;
uint16_t hashISBN(char*);
void test1();
void test2();
char TPBooks[][2][32] = { { "The shepherd's crown", "9780857534811" },
{ "Raising steam", "9780857522276" },
{ "Snuff", "9780385619264" },
{ "I shall wear midnight", "9780552555593" },
{ "Unseen academicals", "9780385609340" },
{ "Making money", "9780385611015" },
{ "Thud!", "9780552152679" },
{ "Going postal", "9780552149433" },
{ "Monstrous Regiment", "9780552154314" },
{ "Night watch", "9780552148993" },
{ "Thief of time", "9780552154260" } };
struct tpBook {
char title[32];
// maybe some other data
} book;
struct tpIsbn {
char isbn[14];
// we need a != operator
bool operator!=(tpIsbn& i) {
char *a = &isbn[0], *b = &i.isbn[0];
for (; *a == *b; a++, b++) {
if (*a == '\0' || *b == '\0') {
if (*a == *b) { return false; }
break; // end of one string
}
}
return true;
}
} key;
int main()
{
test1();
std::cout << "End of Test 1\n";
test2();
std::cout << "End of Test 2\n";
std::cin.get();
return 0;
}
void test2() {
HashTableSC<int, int> hashSC(40);
for (int i = 0; i < 120; i++) {
hashSC.insert(i, i, i); // should get average 3 per slot
}
std::cout << hashSC.count() << " items inserted\n";
for(int i = 80; i < 120; i++) {
hashSC.erase(i, i);
}
std::cout << hashSC.count() << " items remaining\n";
for (int i = 80; i < 120; i++) {
hashSC.insert(i, i, i); // put em back
}
std::cout << hashSC.count() << " items now\n";
for (HashTableSC<int, int>::iterator it = hashSC.begin(); it.hasNext(); it++) {
std::cout << it.first << " " << it.second << '\n';
}
}
void test1() {
HashTableSC<tpBook, tpIsbn> hashSC(20);
for (int i = 0; i < 11; i++) {
strcpy(book.title, TPBooks[i][0]);
strcpy(key.isbn, TPBooks[i][1]);
hashSC.insert(key, book, hashISBN(key.isbn));
}
std::cout << hashSC.count() << " items inserted\n";
for (HashTableSC<tpBook, tpIsbn>::iterator it = hashSC.begin(); it.hasNext(); it++) {
std::cout << it.first.isbn << " " << it.second.title << '\n';
}
tpBook* found = hashSC.find(key, hashISBN(key.isbn));
if (found) {
std::cout << "Found: " << found->title << '\n';
}
else {
std::cout << "Not Found\n";
}
hashSC.erase(key, hashISBN(key.isbn));
std::cout << hashSC.count() << " items remaining\n";
for (HashTableSC<tpBook, tpIsbn>::iterator it = hashSC.begin(); it.hasNext(); it++) {
std::cout << it.first.isbn << " " << it.second.title << '\n';
}
}
uint16_t hashISBN(char *isbn) {
char subStr[9];
subStr[8] = '\0';
// drop leading 4 chars and final check digit
isbn += 4;
strncpy(subStr, isbn, 8);
return (uint16_t)atol(subStr);
}
Or read the chapter in my book C++ Data Structures with immediate download from Amazon