diff --git a/YASI_12/YASI_12.vcxproj b/YASI_12/YASI_12.vcxproj
index d02ea45..8ca9c31 100644
--- a/YASI_12/YASI_12.vcxproj
+++ b/YASI_12/YASI_12.vcxproj
@@ -84,6 +84,7 @@
+
false
diff --git a/YASI_12/YASI_12.vcxproj.filters b/YASI_12/YASI_12.vcxproj.filters
index 8ab932c..f5945f1 100644
--- a/YASI_12/YASI_12.vcxproj.filters
+++ b/YASI_12/YASI_12.vcxproj.filters
@@ -95,5 +95,8 @@
Header Files
+
+ Header Files
+
\ No newline at end of file
diff --git a/YASI_12/ds.doublylinkedlist.h b/YASI_12/ds.doublylinkedlist.h
index 6e8c27f..f904df5 100644
--- a/YASI_12/ds.doublylinkedlist.h
+++ b/YASI_12/ds.doublylinkedlist.h
@@ -105,6 +105,7 @@ namespace ds{
public:
typedef DLLIterator iterator;
+ typedef node_t NodeType;
/////// constructor/destructor ///////////
DoublyLinkedList(){
// make a unit circle: horizon--horizon--horizon
diff --git a/YASI_12/ds.hashtable.h b/YASI_12/ds.hashtable.h
new file mode 100644
index 0000000..34ae839
--- /dev/null
+++ b/YASI_12/ds.hashtable.h
@@ -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 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 IHashFunction{
+public:
+ virtual int operator()(Key n) const = 0;
+};
+
+template
+class IntHashFunction : public IHashFunction{
+public:
+ virtual int operator()(Key n) const override{
+ return n ^ (~n << 11) ^ (n << 3) ^ (~n << 27);
+ }
+};
+
+//template
+//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,
+ class Pred = KVPairEqualityPredicate
+>
+class SeparateChainingHashTable : public HashTableBase<
+ Key,
+ Value,
+ DoublyLinkedList< KVPair >*,
+ HashFunction>
+{
+ ///////////////// enable testing ///////////////////
+ friend class SeparateChainingHashTableTest;
+
+protected:
+ typedef KVPair 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 IntHashTable;
+ typedef KVPair 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
\ No newline at end of file
diff --git a/YASI_12/ds.kvpair.h b/YASI_12/ds.kvpair.h
index 3118427..63989cc 100644
--- a/YASI_12/ds.kvpair.h
+++ b/YASI_12/ds.kvpair.h
@@ -33,5 +33,10 @@ namespace yasi{
return out;
}
- }
-}
\ No newline at end of file
+template
+class KVPairEqualityPredicate{
+public:
+ bool operator() (const Key& k1, const Key& k2){ return k1 == k2; }
+};
+ } // namespace ds
+}// namespace yasi
\ No newline at end of file
diff --git a/YASI_12/main.cpp b/YASI_12/main.cpp
index 137f34a..286f9ee 100644
--- a/YASI_12/main.cpp
+++ b/YASI_12/main.cpp
@@ -7,7 +7,7 @@
#include "ds.binarysearchtree.h"
#include "ds.priorityqueue.h"
#include "ds.BSTDictionary.h"
-
+#include "ds.hashtable.h"
//#include "Sorter.h"
#include