// Hash table set---hash collisions are resolved by placing keys // in conflict with exisiting ones in an STL set (r/b tree) #include #include #include class hash_set; class hash_iter{ // iterator object for hash_set; addresses place of key in HT hash_set *HS; // which hash_set the key is in bool in_primary_table; // flag indicating iterator points into // the primary table unsigned int bucket; // which bucket in points in this case set >::iterator pos; // position if iterator points to secondary storage friend class hash_set; // assigns above members public: hash_iter(void) {} hash_iter(hash_set *); hash_iter& operator++(void); hash_iter operator++(int); bool operator==(const hash_iter& HI) const; key operator*(void); }; // end class hash_iter class hash_set{ unsigned int bucket_count; // size of primary table unsigned int size; // number of keys currently in container vector< pair > primary_table; // for initial probe // primary_table[i].second flags if a key occupies slot i // primary_table[i].first is that key (or key() if none is there) set< key, less > secondary_storage; // for collision resolution public: typedef hash_iter iterator; // defines hash_set::iterator friend class hash_iter; hash_set(int bc) : primary_table(bc, make_pair(key(), false) ), // initializes table unassigned slots bucket_count(bc) {size = 0;} ~hash_set(void) { } iterator begin(void); iterator end(void); pair insert(const key&); iterator find(const key&); };// end class hash_set hash_iter::hash_iter(hash_set *hsp) : HS(hsp), in_primary_table(false) {pos = HS->secondary_storage.end(); } key hash_iter::operator*(void) {if(in_primary_table) return HS->primary_table[bucket].first; else if(pos != HS->secondary_storage.end()) return *pos; else return key();} // dereference beyond end hash_iter hash_set::begin(void) {hash_iter HI(this); if(size==0) return end(); for(int b = 0; b < bucket_count; b++) if(primary_table[b].second) {HI.in_primary_table = true; HI.bucket= b; return HI; } // empty primary table HI.in_primary_table = false; HI.pos = secondary_storage.begin(); return HI; } hash_iter hash_set::end(void) {hash_iter HI(this); HI.in_primary_table = false; HI.pos = secondary_storage.end(); return HI; } pair hash_set::insert(const key& k) {hash_iter HI(this); // to be completed, copy to be returned // get bucket number for key k unsigned int b = k.hash_fun(bucket_count); // check if k is in the primary table if(primary_table[b].second) // flag to indicate an entry if(k == primary_table[b].first) // value at entry // k is already there, make hash_iter that points to old entry {cout << "\"" << k << "\" is already in primary table" << endl; HI.in_primary_table = true; HI.bucket= b; return make_pair(HI, false); } else // k not in primary table, put slot is occupied, // so insert into secondary_storage {pair >::iterator, bool> P = secondary_storage.insert(k); cout << "\"" << k << "\" inserted in secondary storage" << endl; HI.in_primary_table = false; HI.pos = P.first; // the next statement was missing in my original solution // however, some students got it on the final exam! if (P.second) // check if insertion was done size++; return make_pair(HI, P.second); } else // primary_table entry is open, insert value and // and make hash_iter that points to new entry {cout << "inserting " << "\"" << k << "\" at bucket " << b << endl; size++; HI.in_primary_table = true; HI.bucket= b; primary_table[b] = make_pair(k, true); return make_pair(HI, true); } }// end insert hash_set::iterator hash_set::find(const key& k) {hash_iter HI(this); // to be completed and returned // get bucket number for key k unsigned int b = k.hash_fun(bucket_count); if(!primary_table[b].second) return end(); // not in container if(primary_table[b].second && (k == primary_table[b].first)) {// k is found in primary_table HI.in_primary_table = true; HI.bucket= b; return HI; } else // k not in primary table table, search secondary storage {HI.pos = secondary_storage.find(k); HI.in_primary_table = false; return HI; } } hash_iter& hash_iter::operator++(void) // prefix ++ {// go to next item in hashtable; if(in_primary_table) {// find a bucket that contains an element for(int b = bucket+1; b < HS->bucket_count; b++) {if(HS->primary_table[b].second) // found a new item {bucket = b; return *this; } } // at end of primary_table, skip to secondary_storage in_primary_table = false; pos = HS->secondary_storage.begin(); return *this; } else // advance in secondary_storage pos++; return *this; }// end ++. hash_iter hash_iter::operator++(int) // postfix ++ {hash_iter tmp = *this; ++(*this); return tmp; }// end .++ bool hash_iter::operator==(const hash_iter& HI) const {if(HS != HI.HS) return false; if( in_primary_table && !HI.in_primary_table) return false; if(!in_primary_table && HI.in_primary_table) return false; if(in_primary_table && HI.in_primary_table) return bucket == HI.bucket; else return pos == HI.pos; }// end ==