diff --git a/YASI_12/ds.LinearProbingHashTable.h b/YASI_12/ds.LinearProbingHashTable.h index 89ab704..9f0b75c 100644 --- a/YASI_12/ds.LinearProbingHashTable.h +++ b/YASI_12/ds.LinearProbingHashTable.h @@ -32,6 +32,7 @@ namespace ds{ ///////////////// enable testing /////////////////// template FRIEND_TEST_CLASS(LinearProbingHashTableTestBase); + FRIEND_TEST_CLASS(LinearProbingHashTableTest); public: @@ -53,10 +54,10 @@ namespace ds{ inline unsigned int circularNext(const int index) const{ - return modSize(index + 1); + return this->modSize(index + 1); } inline unsigned int circularPrev(const int index) const{ - return modSize(index - 1); + return this->modSize(index - 1); } inline unsigned int circularDiff(const int low, const int high) const{ if (low == high) return 0; @@ -100,7 +101,7 @@ namespace ds{ else{ // non-zero key Pred keyEquals; - unsigned int firstBucket = index(k); + unsigned int firstBucket = this->index(k); int cur = firstBucket; do{ @@ -118,7 +119,7 @@ namespace ds{ } else{ // move on to the next slot - cur = modSize(cur + 1); + cur = this->modSize(cur + 1); } } // } while (cur != firstBucket); @@ -149,7 +150,7 @@ namespace ds{ // try all cells in the table, starting from the first (hashed) bucket // if all cells are occupied, grow the table and keep trying while (true){ - unsigned int firstBucket = index(k); + unsigned int firstBucket = this->index(k); int cur = firstBucket; do{ //Pair* pEntry = table[cur]; @@ -163,7 +164,7 @@ namespace ds{ if (needGrow(_population+1)){ // current bucket is not appropriate anymore under new size // exit the do{} loop, after which we grow and try again - continue; + break; } else{ // create a new entry @@ -181,7 +182,7 @@ namespace ds{ } else{ // move on to the next slot - cur = modSize(cur + 1); + cur = this->modSize(cur + 1); } } // } while (cur != firstBucket); @@ -200,14 +201,16 @@ namespace ds{ _zeroUsed = false; _population--; - if (needShrink(_population)) - shrink(); + // shrink should not be automatic + + //if (needShrink(_population)) + // shrink(); } } else{ // non-zero key Pred keyEquals; - unsigned int curFirstBucket = index(k); + unsigned int curFirstBucket = this->index(k); unsigned int cur = curFirstBucket; const int searchStart = curFirstBucket; // remember our first posti do{ @@ -225,9 +228,13 @@ namespace ds{ // remove removeEntry(cur); _population--; - if (needShrink(_population)) - shrink(); - else{ + + // shrink should not be automatic + + //if (needShrink(_population)) + // shrink(); + //else + { // shuffle the entries from right to left until an empty slot is found // (there must be one because we just deleted one) // this will fix all other's linear probing sequence @@ -242,7 +249,7 @@ namespace ds{ // crossedBoundary = true; //} - unsigned int neighborFirstBucket = index(key(neighbor)); + unsigned int neighborFirstBucket = this->index(key(neighbor)); if (neighborFirstBucket == neighbor || // is the neighbor at its own first bucket? then it should not move ( (curFirstBucket <= cur) // search did not wrap around the end @@ -273,7 +280,7 @@ namespace ds{ else{ // key didn't match // move on to the next slot - cur = modSize(cur + 1); + cur = this->modSize(cur + 1); } } // table[cur] != NULL; go to next iteration of while loop } while (cur != searchStart); diff --git a/YASI_12/ds.LinearProbingHashTable.test.h b/YASI_12/ds.LinearProbingHashTable.test.h index 7f71621..71631c3 100644 --- a/YASI_12/ds.LinearProbingHashTable.test.h +++ b/YASI_12/ds.LinearProbingHashTable.test.h @@ -482,9 +482,13 @@ namespace yasi{ } ASSERT_EQ(16, h1.size()) << "h1 size not 16"; ASSERT_EQ(popLimit, h1.population()) << "h1 pop not " << popLimit; - // this should trigger shrink - h1.remove(j); + // next remove should trigger shrink + ASSERT_EQ(true, h1.needShrink(h1.population() - 1)); + h1.remove(j); // shrink should not be automatic + ASSERT_EQ(16, h1.size()) << "h1 size not " << 16; j--; + // force shrink + h1.shrink(); ASSERT_EQ(8, h1.size()) << "h1 size not " << 8; ASSERT_EQ(popLimit - 1, h1.population()) << "h1 pop not " << popLimit - 1; } diff --git a/YASI_12/ds.arraybinarytree.h b/YASI_12/ds.arraybinarytree.h index 7d8456d..0d6c54e 100644 --- a/YASI_12/ds.arraybinarytree.h +++ b/YASI_12/ds.arraybinarytree.h @@ -90,7 +90,7 @@ namespace yasi{ virtual void fromArray(const E*, const int) = 0; virtual int getRootIndex() const = 0; virtual Node* nodeAt(int) const = 0; - virtual Node* insertAt(const E& e, uint) = 0; + virtual Node* insertAt(const E& e, int) = 0; }; @@ -355,12 +355,17 @@ namespace yasi{ // (1) inserts at arbitrary unoccupied index, increasing the capacity when the index is too large // (2) cannot insert at zero index // (3) does not check parent/child relationship; the node can be possibly without a parent + // (4) if a too large index is specified, runs the risk of memory allocation error // dynamically allocates a new node; increases the tree-size by one // returns the node-ptr on success, NULL on failure - node_t* insertAt(const E& e, uint index) override{ + node_t* insertAt(const E& e, int index) override{ node_t* pNode = NULL; - if (index > 0){ - while (index >= _capacity){ + if (index <= 0) { + // cannot insert at negative or zero index + return NULL; + } + else{ + while ((uint) index >= _capacity){ // need to increase capacity _capacity = (int)(_capacity * LOAD_FACTOR); _arr.resize(_capacity, 0); // newly added values are zero diff --git a/YASI_12/ds.hashtablebase.h b/YASI_12/ds.hashtablebase.h index 973f7d4..d7e5261 100644 --- a/YASI_12/ds.hashtablebase.h +++ b/YASI_12/ds.hashtablebase.h @@ -41,6 +41,33 @@ public: } }; + +class StringHashFunction{ + static const int A = 54059; /* a prime */ + static const int B = 76963; /* another prime */ + static const int C = 86969; /* yet another prime */ +public: + + virtual int operator()(const char* s) const { + unsigned int h = 31 /* also prime */; + while (*s) { + h = (h * A) ^ (s[0] * B); + s++; + } + return h; // or return h % C; + } + virtual int operator()(std::string str) const { + unsigned int h = 31 /* also prime */; + const char* s = str.c_str(); + while (*s) { + h = (h * A) ^ (s[0] * B); + s++; + } + return h; // or return h % C; + } +}; + + // various simplistic hash functions for testing namespace testhash{ template @@ -136,9 +163,9 @@ protected: } inline float density(){ return ((float) _population) / _size; } // true if the specified population would be too dense for current table - inline float needGrow(const int pop) const { return (((float)pop) / _size) >= DENSITY_MAX; } + inline bool needGrow(const int pop) const { return (((float)pop) / _size) >= DENSITY_MAX; } // true if the specified population would be too sparse for current table - inline float needShrink(const int pop) const { return (((float)pop) / _size) <= DENSITY_MIN; } + inline bool needShrink(const int pop) const { return (((float)pop) / _size) <= DENSITY_MIN; } // pure virtual function virtual inline bool isBucketEmpty(const int bucket) const = 0; @@ -213,8 +240,8 @@ public: _size = _population = _logSize = 0; } - inline unsigned int size(){ return _size; } - inline unsigned int population(){ return _population; } + inline unsigned int size() const { return _size; } + inline unsigned int population() const { return _population; } string toString() const{ diff --git a/gtest-1.7.0/msvc/gtest/vc120.idb b/gtest-1.7.0/msvc/gtest/vc120.idb index cc61c5c..677c3e5 100644 Binary files a/gtest-1.7.0/msvc/gtest/vc120.idb and b/gtest-1.7.0/msvc/gtest/vc120.idb differ diff --git a/gtest-1.7.0/msvc/gtestd.lib b/gtest-1.7.0/msvc/gtestd.lib index c303275..66577eb 100644 Binary files a/gtest-1.7.0/msvc/gtestd.lib and b/gtest-1.7.0/msvc/gtestd.lib differ