diff --git a/YASI_12/ds.LinearProbingHashTable.h b/YASI_12/ds.LinearProbingHashTable.h index aac6a75..c2cc248 100644 --- a/YASI_12/ds.LinearProbingHashTable.h +++ b/YASI_12/ds.LinearProbingHashTable.h @@ -26,6 +26,7 @@ namespace ds{ typedef Pair* BucketType; typedef Key KeyType; typedef Value ValueType; + typedef BucketType BucketEntryPtr; // need to change protected: // flag about the usage of the first [0] slot bool _zeroUsed; // true if an entry with key=0 exists @@ -194,6 +195,21 @@ namespace ds{ _zeroUsed = false; _size = _population = _logSize = 0; } + + // for test only + inline BucketType entry(const int bucket) const { + return table[bucket]; + } + inline Key key(const int bucket) const { + return table[bucket]->key; + } + inline Value value(const int bucket) const { + return table[bucket]->value; + } + inline BucketEntryPtr entryPtr(const int bucket) const{ return table[bucket]; } + inline bool isNull(const int bucket) const{ + return table[bucket] == NULL; + } public: LinearProbingHashTable(unsigned int logSize = INIT_LOGSIZE) : _zeroUsed(false), _zeroPair(0,0), HashTableBase(logSize){ @@ -309,6 +325,8 @@ namespace ds{ class LinearProbingHashTableTest : public yasi::Test{ protected: + + template class IdentityFunction : public IHashFunction{ public: @@ -350,29 +368,28 @@ namespace ds{ return n % modulus; } }; + + //bucketKey(h,x) + // h.mytable[0]->key + // h.mytable[bucket]->key + // h.mytable[x]->key + + typedef LinearProbingHashTable, Mod8Function > IntHashTable8; + typedef LinearProbingHashTable, Mod16Function > IntHashTable16; + typedef IntHashTable16 IntHashTable; // default + typedef LinearProbingHashTable, Mod32Function > IntHashTable32; + typedef IntHashTable::BucketType BucketType; + typedef IntHashTable::BucketEntryPtr BucketEntryPtr; + typedef IntHashTable::Pair Pair; + + public: void insert(){ - typedef LinearProbingHashTable, Mod16Function > IntHashTable; - typedef IntHashTable::BucketType BucketType; - typedef IntHashTable::Pair Pair; IntHashTable h(4); ASSERT_EQ(16, h.size()) << "size not 16"; ASSERT_EQ(0, h.population()) << "pop not 0"; - //int newLogSize = 4; // 16 entries - //int newSize = 1 << newLogSize; - //int newPopulation = 0; - //BucketType* newTable = new BucketType[newSize]; - //memset(newTable, 0, sizeof(BucketType*) * newSize); - //IdentityFunction newHashFunction; // maps n to n - //// put some entries into the new table - //newTable[4] = new Pair(4, 4); newPopulation++; - //newTable[5] = new Pair(5, 5); newPopulation++; - //newTable[6] = new Pair(6, 6); newPopulation++; - //// force these state into the hashtable - //h.forceTable(newTable, newLogSize, newPopulation, newHashFunction); - { SCOPED_TRACE("insert 4-5-6"); h.insert(4, 4); @@ -388,24 +405,24 @@ namespace ds{ int key = 20; int bucket = 7; SCOPED_TRACE(str); - Pair* p = h.insertKey(key); + BucketEntryPtr p = h.insertKey(key); p->value = key; // assign the value cout << str << endl << h; - ASSERT_NE(0, (int)h.table[bucket]) << "bucket " << bucket << " NULL"; - ASSERT_EQ(p, h.table[bucket]) << key << " not in bucket " << bucket; - ASSERT_EQ(key, h.table[bucket]->key) << key << " not in bucket " << bucket; + ASSERT_NE(true, h.isNull(bucket)) << "bucket " << bucket << " NULL"; + ASSERT_EQ(p, h.entryPtr(bucket)) << key << " not in bucket " << bucket; + ASSERT_EQ(key, h.key(bucket)) << key << " not in bucket " << bucket; } { string str = "insert 23, which should go to bucket 8"; int key = 23; int bucket = 8; SCOPED_TRACE(str); - Pair* p = h.insertKey(key); + BucketEntryPtr p = h.insertKey(key); p->value = key; // assign the value cout << str << endl << h; - ASSERT_NE(0, (int)h.table[bucket]) << "bucket " << bucket << " NULL"; - ASSERT_EQ(p, h.table[bucket]) << key << " not in bucket " << bucket; - ASSERT_EQ(key, h.table[bucket]->key) << key << " not in bucket " << bucket; + ASSERT_NE(true, h.isNull(bucket)) << "bucket " << bucket << " NULL"; + ASSERT_EQ(p, h.entryPtr(bucket)) << key << " not in bucket " << bucket; + ASSERT_EQ(key, h.key(bucket)) << key << " not in bucket " << bucket; } { string str = "insert 20, which is already in bucket 7"; @@ -413,12 +430,12 @@ namespace ds{ int key = 20; int bucket = 7; SCOPED_TRACE(str); - Pair* p = h.insertKey(key); + BucketEntryPtr p = h.insertKey(key); cout << str << endl << h; - ASSERT_NE(0, (int)h.table[bucket]) << "bucket " << bucket << " NULL"; - ASSERT_EQ(p, h.table[bucket]) << key << " not in bucket " << bucket; - ASSERT_EQ(key, h.table[bucket]->key) << key << " not in bucket " << bucket; - ASSERT_EQ(key, h.table[bucket]->value) << key << " not in bucket " << bucket; + ASSERT_NE(true, h.isNull(bucket)) << "bucket " << bucket << " NULL"; + ASSERT_EQ(p, h.entryPtr(bucket)) << key << " not in bucket " << bucket; + ASSERT_EQ(key, h.key(bucket)) << key << " not in bucket " << bucket; + ASSERT_EQ(key, h.value(bucket)) << key << " not in bucket " << bucket; } { h.insert(13, 13); @@ -429,12 +446,12 @@ namespace ds{ int key = 16; int bucket = 0; SCOPED_TRACE(str); - Pair* p = h.insertKey(key); + BucketEntryPtr p = h.insertKey(key); p->value = key; // assign the value cout << str << endl << h; - ASSERT_NE(0, (int)h.table[bucket]) << "bucket " << bucket << " NULL"; - ASSERT_EQ(p, h.table[bucket]) << key << " not in bucket " << bucket; - ASSERT_EQ(key, h.table[bucket]->key) << key << " not in bucket " << bucket; + ASSERT_NE(true, h.isNull(bucket)) << "bucket " << bucket << " NULL"; + ASSERT_EQ(p, h.entryPtr(bucket)) << key << " not in bucket " << bucket; + ASSERT_EQ(key, h.key(bucket)) << key << " not in bucket " << bucket; } { @@ -442,12 +459,12 @@ namespace ds{ int key = 29; int bucket = 1; SCOPED_TRACE(str); - Pair* p = h.insertKey(key); + BucketEntryPtr p = h.insertKey(key); p->value = key; // assign the value cout << str << endl << h; - ASSERT_NE(0, (int)h.table[bucket]) << "bucket " << bucket << " NULL"; - ASSERT_EQ(p, h.table[bucket]) << key << " not in bucket " << bucket; - ASSERT_EQ(key, h.table[bucket]->key) << key << " not in bucket " << bucket; + ASSERT_NE(true, h.isNull(bucket)) << "bucket " << bucket << " NULL"; + ASSERT_EQ(p, h.entryPtr(bucket)) << key << " not in bucket " << bucket; + ASSERT_EQ(key, h.key(bucket)) << key << " not in bucket " << bucket; } { @@ -456,7 +473,7 @@ namespace ds{ SCOPED_TRACE(str); ASSERT_EQ(false, h._zeroUsed) << "_zeroUsed true"; int prevPop = h.population(); - Pair* p = h.insertKey(key); + BucketEntryPtr p = h.insertKey(key); p->value = 100; // assign the value cout << str << endl << h; ASSERT_EQ(true, h._zeroUsed) << "_zeroUsed false"; @@ -468,13 +485,9 @@ namespace ds{ } void copyTable(){ - typedef LinearProbingHashTable, ModFunction > IntHashTable; - typedef IntHashTable::BucketType BucketType; - typedef IntHashTable::Pair Pair; - IntHashTable h1(4), h2(5); - h1.hash.modulus = 16; - h2.hash.modulus = 32; + IntHashTable16 h1(4); + IntHashTable32 h2(5); ASSERT_EQ(16, h1.size()) << "h1 size not 16"; ASSERT_EQ(0, h1.population()) << "h1 pop not 0"; @@ -499,9 +512,9 @@ namespace ds{ // items are rehashed mod 32 for (int i = 0; i < h1._size; i++){ if (h1.table[i]){ - int key = h1.table[i]->key; - int value = h1.table[i]->value; - Pair* p = h2.lookupKey(key); + int key = h1.key(i); + int value = h1.value(i); + BucketEntryPtr p = h2.lookupKey(key); ASSERT_NE(0, (int)p) << "key " << key << " not found in h2"; ASSERT_EQ(key, p->key) << "key " << key << " mismatch in h2 key " << p->key; ASSERT_EQ(value, p->value) << "value " << value << " mismatch in h2 key " << p->key << "value: " << p->value; @@ -512,10 +525,6 @@ namespace ds{ } void remove(){ - typedef LinearProbingHashTable, Mod16Function > IntHashTable; - typedef LinearProbingHashTable, Mod8Function > IntHashTable8; - typedef IntHashTable::BucketType BucketType; - typedef IntHashTable::Pair Pair; IntHashTable h(4); ASSERT_EQ(16, h.size()) << "size not 16"; @@ -547,9 +556,9 @@ namespace ds{ cout << h; ASSERT_EQ(16, h.size()) << "size not 16"; ASSERT_EQ(NULL, (int)h.lookupKey(4)) << "key " << 4 << " not NULL"; - ASSERT_EQ(5, h.table[5]->key) << "[5] not " << 5; - ASSERT_EQ(6, h.table[6]->key) << "[6] not " << 6; - ASSERT_EQ(7, h.table[7]->key) << "[7] not " << 7; + ASSERT_EQ(5, h.key(5)) << "[5] not " << 5; + ASSERT_EQ(6, h.key(6)) << "[6] not " << 6; + ASSERT_EQ(7, h.key(7)) << "[7] not " << 7; ASSERT_EQ(7, h.population()) << "population not 7"; } { @@ -562,8 +571,8 @@ namespace ds{ ASSERT_EQ(6, h.population()) << "population not 6"; cout << "after removing 6\n" << h; ASSERT_EQ(NULL, (int)h.lookupKey(6)) << "key " << 6 << " not NULL"; - ASSERT_EQ(5, h.table[5]->key) << "key " << 5 << " misplaced"; - ASSERT_EQ(7, h.table[7]->key) << "key " << 7 << " misplaced"; + ASSERT_EQ(5, h.key(5)) << "key " << 5 << " misplaced"; + ASSERT_EQ(7, h.key(7)) << "key " << 7 << " misplaced"; } { SCOPED_TRACE("remove simple 2-item bucket"); @@ -571,21 +580,21 @@ namespace ds{ //// 46 - - - - 5 85 7 - - - - 12 - 14 30 //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ASSERT_EQ(7, h.population()) << "population not 7"; - ASSERT_EQ(85, h.table[6]->key) << "[6] not 85"; + ASSERT_EQ(85, h.key(6)) << "[6] not 85"; ASSERT_EQ(16, h.size()) << "size not 16"; h.remove(5); //// 46 - - - - 85 - 7 - - - - 12 - 14 30 //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ASSERT_EQ(NULL, (int)h.lookupKey(5)) << "key " << 5 << " not NULL"; - ASSERT_EQ(85, h.table[5]->key) << "key " << 85 << " misplaced"; - ASSERT_EQ(NULL, (int)h.table[6]) << "[6] not NULL"; - ASSERT_EQ(7, h.table[7]->key) << "key " << 7 << " misplaced"; + ASSERT_EQ(85, h.key(5)) << "key " << 85 << " misplaced"; + ASSERT_EQ(true, h.isNull(6)) << "[6] not NULL"; + ASSERT_EQ(7, h.key(7)) << "key " << 7 << " misplaced"; // put 5 back h.insert(5,5); //// 46 - - - - 85 5 7 - - - - 12 - 14 30 //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - ASSERT_EQ(5, h.table[6]->key) << "key " << 5 << " misplaced"; + ASSERT_EQ(5, h.key(6)) << "key " << 5 << " misplaced"; // delete 5 h.remove(5); @@ -593,9 +602,9 @@ namespace ds{ //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ASSERT_EQ(16, h.size()) << "size not 16"; ASSERT_EQ(NULL, (int)h.lookupKey(5)) << "key " << 5 << " not NULL"; - ASSERT_EQ(85, h.table[5]->key) << "key " << 85 << " misplaced"; - ASSERT_EQ(NULL, (int)h.table[6]) << "[6] not NULL"; - ASSERT_EQ(7, h.table[7]->key) << "key " << 7 << " misplaced"; + ASSERT_EQ(85, h.key(5)) << "key " << 85 << " misplaced"; + ASSERT_EQ(true, h.isNull(6)) << "[6) not NULL"; + ASSERT_EQ(7, h.key(7)) << "key " << 7 << " misplaced"; // for consistency later on, replace 85 with 5 h.remove(85); @@ -603,9 +612,9 @@ namespace ds{ //// 46 - - - - 5 - 7 - - - - 12 - 14 30 //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ASSERT_EQ(16, h.size()) << "size not 16"; - ASSERT_EQ(5, h.table[5]->key) << "[5] not 5"; - ASSERT_EQ(NULL, (int)h.table[6]) << "[6] not NULL"; - ASSERT_EQ(7, h.table[7]->key) << "key " << 7 << " misplaced"; + ASSERT_EQ(5, h.key(5)) << "[5] not 5"; + ASSERT_EQ(true, h.isNull(6)) << "[6] not NULL"; + ASSERT_EQ(7, h.key(7)) << "key " << 7 << " misplaced"; } // add several entries that map into bucket 5 @@ -636,16 +645,16 @@ namespace ds{ cout << "after removing 5:\n" << h << endl; ASSERT_EQ(16, h.size()) << "size not 16"; ASSERT_EQ(NULL, (int)h.lookupKey(5)) << "key " << 5 << " not NULL"; - ASSERT_EQ(21, h.table[5]->key) << "[5] not 21"; - ASSERT_EQ(37, h.table[6]->key) << "[6] not 37"; - ASSERT_EQ(7, h.table[7]->key) << "[7] not 7"; - ASSERT_EQ(53, h.table[8]->key) << "[8] not 53"; - ASSERT_EQ(23, h.table[9]->key) << "[9] not 23"; - ASSERT_EQ(39, h.table[10]->key) << "[10] not 39"; - ASSERT_EQ(NULL, (int)h.table[11]) << "[11] not NULL"; - ASSERT_EQ(12, h.table[12]->key) << "[12] not 12"; - ASSERT_EQ(NULL, (int)h.table[13]) << "[13] not NULL"; - ASSERT_EQ(14, h.table[14]->key) << "[14] not 14"; + ASSERT_EQ(21, h.key(5)) << "[5] not 21"; + ASSERT_EQ(37, h.key(6)) << "[6] not 37"; + ASSERT_EQ(7, h.key(7)) << "[7] not 7"; + ASSERT_EQ(53, h.key(8)) << "[8] not 53"; + ASSERT_EQ(23, h.key(9)) << "[9] not 23"; + ASSERT_EQ(39, h.key(10)) << "[10] not 39"; + ASSERT_EQ(true, h.isNull(11)) << "[11] not NULL"; + ASSERT_EQ(12, h.key(12)) << "[12] not 12"; + ASSERT_EQ(true, h.isNull(13)) << "[13] not NULL"; + ASSERT_EQ(14, h.key(14)) << "[14] not 14"; } { SCOPED_TRACE("remove 21"); @@ -655,16 +664,16 @@ namespace ds{ //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ASSERT_EQ(16, h.size()) << "size not 16"; ASSERT_EQ(NULL, (int)h.lookupKey(21)) << "key " << 21 << " not NULL"; - ASSERT_EQ(37, h.table[5]->key) << "[5] not 37"; - ASSERT_EQ(53, h.table[6]->key) << "[6] not 53"; - ASSERT_EQ(7, h.table[7]->key) << "[7] not 7"; - ASSERT_EQ(23, h.table[8]->key) << "[8] not 23"; - ASSERT_EQ(39, h.table[9]->key) << "[9] not 39"; - ASSERT_EQ(NULL, (int)h.table[10]) << "[10] not NULL"; - ASSERT_EQ(NULL, (int)h.table[11]) << "[11] not NULL"; - ASSERT_EQ(12, h.table[12]->key) << "[12] not 12"; - ASSERT_EQ(NULL, (int)h.table[13]) << "[13] not NULL"; - ASSERT_EQ(14, h.table[14]->key) << "[14] not 14"; + ASSERT_EQ(37, h.key(5)) << "[5] not 37"; + ASSERT_EQ(53, h.key(6)) << "[6] not 53"; + ASSERT_EQ(7, h.key(7)) << "[7] not 7"; + ASSERT_EQ(23, h.key(8)) << "[8] not 23"; + ASSERT_EQ(39, h.key(9)) << "[9] not 39"; + ASSERT_EQ(true, h.isNull(10)) << "[10] not NULL"; + ASSERT_EQ(true, h.isNull(11)) << "[11] not NULL"; + ASSERT_EQ(12, h.key(12)) << "[12] not 12"; + ASSERT_EQ(true, h.isNull(13)) << "[13] not NULL"; + ASSERT_EQ(14, h.key(14)) << "[14] not 14"; } { @@ -675,22 +684,22 @@ namespace ds{ //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ASSERT_EQ(16, h.size()) << "size not 16"; ASSERT_EQ(NULL, (int)h.lookupKey(23)) << "key " << 23 << " not NULL"; - ASSERT_EQ(37, h.table[5]->key) << "[5] not 37"; - ASSERT_EQ(53, h.table[6]->key) << "[6] not 53"; - ASSERT_EQ(7, h.table[7]->key) << "[7] not 7"; - ASSERT_EQ(39, h.table[8]->key) << "[8] not 39"; - ASSERT_EQ(NULL, (int)h.table[9]) << "[9] not NULL"; - ASSERT_EQ(NULL, (int)h.table[10]) << "[10] not NULL"; - ASSERT_EQ(NULL, (int)h.table[11]) << "[11] not NULL"; - ASSERT_EQ(12, h.table[12]->key) << "[12] not 12"; - ASSERT_EQ(NULL, (int)h.table[13]) << "[13] not NULL"; - ASSERT_EQ(14, h.table[14]->key) << "[14] not 14"; + ASSERT_EQ(37, h.key(5)) << "[5] not 37"; + ASSERT_EQ(53, h.key(6)) << "[6] not 53"; + ASSERT_EQ(7, h.key(7)) << "[7] not 7"; + ASSERT_EQ(39, h.key(8)) << "[8] not 39"; + ASSERT_EQ(true, h.isNull(9)) << "[9] not NULL"; + ASSERT_EQ(true, h.isNull(10)) << "[10] not NULL"; + ASSERT_EQ(true, h.isNull(11)) << "[11] not NULL"; + ASSERT_EQ(12, h.key(12)) << "[12] not 12"; + ASSERT_EQ(true, h.isNull(13)) << "[13] not NULL"; + ASSERT_EQ(14, h.key(14)) << "[14] not 14"; } h.insert(62, 62); h.insert(17, 17); //// 46 62 17 - - 37 53 39 - - - - 12 - 14 30 //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - ASSERT_EQ(62, h.table[1]->key) << "[1] not 62"; + ASSERT_EQ(62, h.key(1)) << "[1] not 62"; { SCOPED_TRACE("remove 46"); @@ -702,11 +711,11 @@ namespace ds{ cout << "after removing 46:\n" << h << endl; ASSERT_EQ(16, h.size()) << "size not 16"; ASSERT_EQ(NULL, (int)h.lookupKey(46)) << "key " << 46 << " not NULL"; - ASSERT_EQ(62, h.table[0]->key) << "[0] not 62"; - ASSERT_EQ(17, h.table[1]->key) << "[1] not 17"; - ASSERT_EQ(NULL, (int)h.table[2]) << "[2] not NULL"; - ASSERT_EQ(14, h.table[14]->key) << "[14] not 14"; - ASSERT_EQ(30, h.table[15]->key) << "[15] not 30"; + ASSERT_EQ(62, h.key(0)) << "[0] not 62"; + ASSERT_EQ(17, h.key(1)) << "[1] not 17"; + ASSERT_EQ(true, h.isNull(2)) << "[2] not NULL"; + ASSERT_EQ(14, h.key(14)) << "[14] not 14"; + ASSERT_EQ(30, h.key(15)) << "[15] not 30"; } { @@ -717,10 +726,10 @@ namespace ds{ //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ASSERT_EQ(16, h.size()) << "size not 16"; ASSERT_EQ(NULL, (int)h.lookupKey(30)) << "key " << 30 << " not NULL"; - ASSERT_EQ(17, h.table[1]->key) << "[1] not 17"; - ASSERT_EQ(NULL, (int)h.table[0]) << "[0] not NULL"; - ASSERT_EQ(14, h.table[14]->key) << "[14] not 14"; - ASSERT_EQ(62, h.table[15]->key) << "[15] not 62"; + ASSERT_EQ(17, h.key(1)) << "[1] not 17"; + ASSERT_EQ(true, h.isNull(0)) << "[0] not NULL"; + ASSERT_EQ(14, h.key(14)) << "[14] not 14"; + ASSERT_EQ(62, h.key(15)) << "[15] not 62"; } { SCOPED_TRACE("remove 14"); @@ -730,8 +739,8 @@ namespace ds{ //// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ASSERT_EQ(16, h.size()) << "size not 16"; ASSERT_EQ(NULL, (int)h.lookupKey(14)) << "key " << 14 << " not NULL"; - ASSERT_EQ(62, h.table[14]->key) << "[14] not 62"; - ASSERT_EQ(NULL, (int)h.table[15]) << "[15] not NULL"; + ASSERT_EQ(62, h.key(14)) << "[14] not 62"; + ASSERT_EQ(true, h.isNull(15)) << "[15] not NULL"; } } @@ -752,7 +761,7 @@ namespace ds{ { SCOPED_TRACE("remove from an all-filled table"); // create a pathological table - Pair** badTable = new Pair*[8]; // 8 entries in the table + BucketEntryPtr* badTable = new BucketEntryPtr[8]; // 8 entries in the table for (int i = 0; i < 8; i++){ badTable[i] = new Pair(5, i); // all keys are 5 } @@ -771,10 +780,10 @@ namespace ds{ ASSERT_EQ(7, h2.population()) << "population not 7"; for (int i = 0; i < 8; i++){ if (i == 4){ - ASSERT_EQ(NULL, (int)h2.table[i]) << "[" << i << "] not NULL"; + ASSERT_EQ(true, h2.isNull(i)) << "[" << i << "] not NULL"; } else - ASSERT_EQ(5, h2.table[i]->key) << "[" << i << "] not 5"; + ASSERT_EQ(5, h2.key(i)) << "[" << i << "] not 5"; } } @@ -782,14 +791,9 @@ namespace ds{ } } - + void growCondition(){ - typedef LinearProbingHashTable, ModFunction > IntHashTable; - typedef IntHashTable::BucketType BucketType; - typedef IntHashTable::Pair Pair; - - IntHashTable h1(4); - h1.hash.modulus = 16; + IntHashTable16 h1(4); int i = 0; { @@ -811,12 +815,7 @@ namespace ds{ } } void shrinkCondition(){ - typedef LinearProbingHashTable, ModFunction > IntHashTable; - typedef IntHashTable::BucketType BucketType; - typedef IntHashTable::Pair Pair; - - IntHashTable h1(4); - h1.hash.modulus = 16; + IntHashTable16 h1(4); int i = 0; {