Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Fixed a bug in LinearProbingHashTable::insertKey()
Added StringHashFunction in HashTableBase.h

Signed-off-by: saq10002 <saad0105050@gmail.com>
  • Loading branch information
saq10002 committed Oct 25, 2014
1 parent 1fcb3f6 commit 7947461
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 25 deletions.
37 changes: 22 additions & 15 deletions YASI_12/ds.LinearProbingHashTable.h
Expand Up @@ -32,6 +32,7 @@ namespace ds{
///////////////// enable testing ///////////////////
template<typename A, typename B, typename C>
FRIEND_TEST_CLASS(LinearProbingHashTableTestBase);

FRIEND_TEST_CLASS(LinearProbingHashTableTest);

public:
Expand All @@ -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;
Expand Down Expand Up @@ -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{

Expand All @@ -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);
Expand Down Expand Up @@ -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];
Expand All @@ -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
Expand All @@ -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);
Expand All @@ -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{
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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);
Expand Down
8 changes: 6 additions & 2 deletions YASI_12/ds.LinearProbingHashTable.test.h
Expand Up @@ -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;
}
Expand Down
13 changes: 9 additions & 4 deletions YASI_12/ds.arraybinarytree.h
Expand Up @@ -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;
};


Expand Down Expand Up @@ -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
Expand Down
35 changes: 31 additions & 4 deletions YASI_12/ds.hashtablebase.h
Expand Up @@ -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<class Key>
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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{
Expand Down
Binary file modified gtest-1.7.0/msvc/gtest/vc120.idb
Binary file not shown.
Binary file modified gtest-1.7.0/msvc/gtestd.lib
Binary file not shown.

0 comments on commit 7947461

Please sign in to comment.