Skip to content

Commit

Permalink
Separate Chaining needs testing.
Browse files Browse the repository at this point in the history
  • Loading branch information
saad0105050 committed Sep 12, 2014
1 parent cc44183 commit b8fbafd
Show file tree
Hide file tree
Showing 6 changed files with 251 additions and 3 deletions.
1 change: 1 addition & 0 deletions YASI_12/YASI_12.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
<ClInclude Include="ds.comparable.h" />
<ClInclude Include="ds.dictionary.h" />
<ClInclude Include="ds.doublylinkedlist.h" />
<ClInclude Include="ds.hashtable.h" />
<ClInclude Include="ds.iterator.h">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</ExcludedFromBuild>
</ClInclude>
Expand Down
3 changes: 3 additions & 0 deletions YASI_12/YASI_12.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,8 @@
<ClInclude Include="test.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ds.hashtable.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
1 change: 1 addition & 0 deletions YASI_12/ds.doublylinkedlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ namespace ds{

public:
typedef DLLIterator<E, Node> iterator;
typedef node_t NodeType;
/////// constructor/destructor ///////////
DoublyLinkedList(){
// make a unit circle: horizon--horizon--horizon
Expand Down
238 changes: 238 additions & 0 deletions YASI_12/ds.hashtable.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
#pragma once
#include "common.h"
#include "ds.kvpair.h"
#include "ds.doublylinkedlist.h"
using namespace std;

namespace yasi{
namespace ds{

template<class Key, class Value = Key>
class IKeyValueStore{
public:
virtual ~IKeyValueStore(){}
virtual Value* get(const Key&) const = 0;
virtual void put(const Key&, const Value&) = 0;
virtual bool contains(const Key&) const = 0;
virtual void remove(const Key&) = 0;
};

template<class Key>
class IHashFunction{
public:
virtual int operator()(Key n) const = 0;
};

template<class Key>
class IntHashFunction : public IHashFunction<Key>{
public:
virtual int operator()(Key n) const override{
return n ^ (~n << 11) ^ (n << 3) ^ (~n << 27);
}
};

//template<class Bucket, class Key>
//class ICollisionStrategy{
//
//public:
// virtual ~ICollisionResolutionStrategy(){}
// // either returns a ptr to the bucket-index, or NULL if no bucket found
// virtual int* findBucket(const Key& k, (void*)pHashTable) = 0;
//};


template< class Key,
class Value,
class BucketType,
class HashFunction
>
class HashTableBase : public IKeyValueStore < Key, Value >{
protected:
// size of the table
// must be a power of two
unsigned int _size;
unsigned int _logSize;
// actual number of keys stored in the table
unsigned int _population;
// the buckets array
BucketType* table;
// the hash function
HashFunction hash;
inline int index(const Key& k) const{
return hash(k) & ((1 << _logSize) - 1); // hash(k) % _size
}
BucketType& bucket(const Key& k) const{
return table[index(k)];
}
public:
// the type of the entries in the hash table
HashTableBase():HashTableBase(6){}
HashTableBase(unsigned int logSize) : _logSize(logSize), _size(1 << logSize), _population(0){
table = new BucketType[_size];
// initialize to zero
memset(table, 0, _size * sizeof(BucketType));
}
virtual ~HashTableBase(){ DELETE_ARR_SAFE(table); _size = _population = 0; }
};


// Separate chaining collision resolution strategy
// each bucket holds a list of values mapped into that bucket
template<
class Key,
class Value = Key,
class HashFunction = IntHashFunction<int>,
class Pred = KVPairEqualityPredicate<Key>
>
class SeparateChainingHashTable : public HashTableBase<
Key,
Value,
DoublyLinkedList< KVPair<Key,Value> >*,
HashFunction>
{
///////////////// enable testing ///////////////////
friend class SeparateChainingHashTableTest;

protected:
typedef KVPair<Key, Value> Pair;
typedef DoublyLinkedList < Pair > List;
typedef typename List::NodeType Node;
public:
typedef List* BucketType;
protected:
// returns the pointer to the value if exists, otherwise returns NULL
Node* bucketNode(BucketType pList, const Key& k) const{
Pred keyEquals;
for (List::iterator n = pList->begin(); n != pList->end(); n++){
if (keyEquals((*n).key,k)){
// found node;
return n.pNode;
}
}
return NULL;
}
Pair* bucketEntry(BucketType pList, const Key& k) const{
Pred keyEquals;
for (List::iterator n = pList->begin(); n != pList->end(); n++){
if (keyEquals((*n).key, k)){
// found node;
return & (n.pNode->element);
}
}
return NULL;
}
bool bucketContains(BucketType pList, const Key& k) const{
Pred keyEquals;
for (List::iterator n = pList->begin(); n != pList->end(); n++){
if (keyEquals((*n).key, k)){
// found node;
return true;
}
}
return false;
}
public:
typedef Key KeyType;
typedef Value ValueType;

virtual ~SeparateChainingHashTable(){
if (table){
for (int i = 0; i < _size; i++){
// each entry is either NULL or a List*
if (table[i]){
table[i]->clear();
DELETE_SAFE(table[i]);
}
}
}
}
SeparateChainingHashTable() :SeparateChainingHashTable(6){}
SeparateChainingHashTable(unsigned int logSize) : HashTableBase(logSize){

//collisionHandler(this);
}
// returns true on success, false on failure
virtual void put(const Key& k, const Value& v) override{
int i = index(k);
BucketType pList = table[i];
if (pList == NULL){
// empty slot; create a new list
pList = new List();
// pushFront for better temporal locality
pList->pushFront(Pair(k, v));
_population++;
}
else{
// existing bucket
Pair* pEntry = bucketEntry(pList, k);
if (pEntry){
// key already exists; update value
pEntry->value = v;
}
else{
pList->pushFront(Pair(k, v));
_population++;
}
}
}
virtual Value* get(const Key& k) const override{
int i = index(k);
BucketType pList = table[i];
if (pList != NULL){
// existing bucket
Pair* pEntry = bucketEntry(pList, k);
if (pEntry)
return &pEntry->value;
}
return NULL;
}
virtual void remove(const Key& k) override{
int i = index(k);
BucketType pList = table[i];
if (pList == NULL){
// the key is absent
// nothing to do
}
else{
// existing bucket
Node* pNode = bucketNode(pList, k);
if (pNode){
pList->remove(pNode);
_population--;
}
}
}
virtual bool contains(const Key& k) const override{
int i = index(k);
BucketType pList = table[i];
if (pList != NULL){
// existing bucket
return bucketContains(pList,k);
}
return false;
}

int size(){ return _size; }
int population(){ return _population; }

};

class SeparateChainingHashTableTest : public yasi::Test{
protected:
typedef SeparateChainingHashTable<int, int> IntHashTable;
typedef KVPair<int, int> Pair;
typedef IntHashTable::BucketType BucketType;

IntHashTable h;
public:

void hashCode(){
// hashcode must be within range
ASSERT_LT(h.index(10), h.size()) << "index(10) out of range";
}
};

ADD_TEST_F(SeparateChainingHashTableTest, hashCode);

} // namespace ds
} // namespace yasi
9 changes: 7 additions & 2 deletions YASI_12/ds.kvpair.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,10 @@ namespace yasi{
return out;
}

}
}
template<class Key>
class KVPairEqualityPredicate{
public:
bool operator() (const Key& k1, const Key& k2){ return k1 == k2; }
};
} // namespace ds
}// namespace yasi
2 changes: 1 addition & 1 deletion YASI_12/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include "ds.binarysearchtree.h"
#include "ds.priorityqueue.h"
#include "ds.BSTDictionary.h"

#include "ds.hashtable.h"
//#include "Sorter.h"

#include <cstdlib>
Expand Down

0 comments on commit b8fbafd

Please sign in to comment.