From b8fbafd9a5f0621252e6386090651d2e9153fa66 Mon Sep 17 00:00:00 2001 From: saad0105050 Date: Fri, 12 Sep 2014 05:26:39 -0400 Subject: [PATCH] Separate Chaining needs testing. --- YASI_12/YASI_12.vcxproj | 1 + YASI_12/YASI_12.vcxproj.filters | 3 + YASI_12/ds.doublylinkedlist.h | 1 + YASI_12/ds.hashtable.h | 238 ++++++++++++++++++++++++++++++++ YASI_12/ds.kvpair.h | 9 +- YASI_12/main.cpp | 2 +- 6 files changed, 251 insertions(+), 3 deletions(-) create mode 100644 YASI_12/ds.hashtable.h 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