📄 hash.cc
字号:
// hash.cc // Routines to manage a self-expanding hash table of arbitrary things.// The hashing function is supplied by the objects being put into// the table; we use chaining to resolve hash conflicts.//// The hash table is implemented as an array of sorted lists,// and we expand the hash table if the number of elements in the table// gets too big.// // NOTE: Mutual exclusion must be provided by the caller.//// Copyright (c) 1992-1996 The Regents of the University of California.// All rights reserved. See copyright.h for copyright notice and limitation // of liability and disclaimer of warranty provisions.const int InitialBuckets = 4; // how big a hash table do we start withconst int ResizeRatio = 3; // when do we grow the hash table?const int IncreaseSizeBy = 4; // how much do we grow table when needed?#include "copyright.h"//----------------------------------------------------------------------// HashTable<Key,T>::HashTable// Initialize a hash table, empty to start with.// Elements can now be added to the table.//----------------------------------------------------------------------template <class Key, class T>HashTable<Key,T>::HashTable(Key (*get)(T x), unsigned (*hFunc)(Key x)){ numItems = 0; InitBuckets(InitialBuckets); getKey = get; hash = hFunc;}//----------------------------------------------------------------------// HashTable<Key,T>::InitBuckets// Initialize the bucket array for a hash table.// Called by the constructor and by ReHash().//----------------------------------------------------------------------template <class Key, class T>voidHashTable<Key,T>::InitBuckets(int sz){ numBuckets = sz; buckets = new Bucket[numBuckets]; for (int i = 0; i < sz; i++) { buckets[i] = new List<T>; }}//----------------------------------------------------------------------// HashTable<T>::~HashTable// Prepare a hash table for deallocation. //----------------------------------------------------------------------template <class Key, class T>HashTable<Key,T>::~HashTable(){ ASSERT(IsEmpty()); // make sure table is empty DeleteBuckets(buckets, numBuckets);}//----------------------------------------------------------------------// HashTable<Key,T>::DeleteBuckets// De-Initialize the bucket array for a hash table.// Called by the destructor and by ReHash().//----------------------------------------------------------------------template <class Key, class T>voidHashTable<Key,T>::DeleteBuckets(List<T> **table, int sz){ for (int i = 0; i < sz; i++) { delete table[i]; } delete [] table;}//----------------------------------------------------------------------// HashTable<Key,T>::HashValue// Return hash table bucket that would contain key.//----------------------------------------------------------------------template <class Key, class T>intHashTable<Key, T>::HashValue(Key key) const { int result = (*hash)(key) % numBuckets; ASSERT(result >= 0 && result < numBuckets); return result;}//----------------------------------------------------------------------// HashTable<Key,T>::Insert// Put an item into the hashtable.// // Resize the table if the # of elements / # of buckets is too big.// Then allocate a HashElement to keep track of the key, item pair,// and add it to the right bucket.//// "key" is the key we'll use to find this item.// "item" is the thing to put in the table.//----------------------------------------------------------------------template <class Key, class T>voidHashTable<Key,T>::Insert(T item){ Key key = getKey(item); ASSERT(!IsInTable(key)); if ((numItems / numBuckets) >= ResizeRatio) { ReHash(); } buckets[HashValue(key)]->Append(item); numItems++; ASSERT(IsInTable(key));}//----------------------------------------------------------------------// HashTable<Key,T>::ReHash// Increase the size of the hashtable, by // (i) making a new table// (ii) moving all the elements into the new table// (iii) deleting the old table//----------------------------------------------------------------------template <class Key, class T>voidHashTable<Key,T>::ReHash(){ Bucket *oldTable = buckets; int oldSize = numBuckets; T item; SanityCheck(); InitBuckets(numBuckets * IncreaseSizeBy); for (int i = 0; i < oldSize; i++) { while (!oldTable[i]->IsEmpty()) { item = oldTable[i]->RemoveFront(); buckets[HashValue(getKey(item))]->Append(item); } } DeleteBuckets(oldTable, oldSize); SanityCheck();}//----------------------------------------------------------------------// HashTable<Key,T>::FindInBucket// Find an item in a hash table bucket, from it's key//// "bucket" -- the list storing the item, if it's in the table // "key" -- the key uniquely identifying the item// // Returns:// Whether item is found, and if found, the item.//----------------------------------------------------------------------template <class Key, class T>boolHashTable<Key,T>::FindInBucket(int bucket, Key key, T *itemPtr) const{ ListIterator<T> iterator(buckets[bucket]); for (; !iterator.IsDone(); iterator.Next()) { if (key == getKey(iterator.Item())) { // found! *itemPtr = iterator.Item(); return TRUE; } } *itemPtr = NULL; return FALSE;}//----------------------------------------------------------------------// HashTable<Key,T>::Find// Find an item from the hash table.// // Returns:// The item or NULL if not found. //----------------------------------------------------------------------template <class Key, class T>boolHashTable<Key,T>::Find(Key key, T *itemPtr) const{ int bucket = HashValue(key); return FindInBucket(bucket, key, itemPtr); }//----------------------------------------------------------------------// HashTable<Key,T>::Remove// Remove an item from the hash table. The item must be in the table.// // Returns:// The removed item.//----------------------------------------------------------------------template <class Key, class T>THashTable<Key,T>::Remove(Key key){ int bucket = HashValue(key); T item; bool found = FindInBucket(bucket, key, &item); ASSERT(found); // item must be in table buckets[bucket]->Remove(item); numItems--; ASSERT(!IsInTable(key)); return item;}//----------------------------------------------------------------------// HashTable<Key,T>::Apply// Apply function to every item in the hash table.//// "func" -- the function to apply//----------------------------------------------------------------------template <class Key,class T>voidHashTable<Key,T>::Apply(void (*func)(T)) const{ for (int bucket = 0; bucket < numBuckets; bucket++) { buckets[bucket]->Apply(func); }}//----------------------------------------------------------------------// HashTable<Key,T>::FindNextFullBucket// Find the next bucket in the hash table that has any items in it.//// "bucket" -- where to start looking for full buckets//----------------------------------------------------------------------template <class Key,class T>intHashTable<Key,T>::FindNextFullBucket(int bucket) const{ for (; bucket < numBuckets; bucket++) { if (!buckets[bucket]->IsEmpty()) { break; } } return bucket;}//----------------------------------------------------------------------// HashTable<Key,T>::SanityCheck// Test whether this is still a legal hash table.//// Tests: are all the buckets legal?// does the table have the right # of elements?// do all the elements hash to where they are stored?//----------------------------------------------------------------------template <class Key, class T>void HashTable<Key,T>::SanityCheck() const{ int numFound = 0; ListIterator<T> *iterator; for (int i = 0; i < numBuckets; i++) { buckets[i]->SanityCheck(); numFound += buckets[i]->NumInList(); iterator = new ListIterator<T>(buckets[i]); for (; !iterator->IsDone(); iterator->Next()) { ASSERT(i == HashValue(getKey(iterator->Item()))); } delete iterator; } ASSERT(numItems == numFound);}//----------------------------------------------------------------------// HashTable<Key,T>::SelfTest// Test whether this module is working.//----------------------------------------------------------------------template <class Key, class T>void HashTable<Key,T>::SelfTest(T *p, int numEntries){ int i; HashIterator<Key, T> *iterator = new HashIterator<Key,T>(this); SanityCheck(); ASSERT(IsEmpty()); // check that table is empty in various ways for (; !iterator->IsDone(); iterator->Next()) { ASSERTNOTREACHED(); } delete iterator; for (i = 0; i < numEntries; i++) { Insert(p[i]); ASSERT(IsInTable(getKey(p[i]))); ASSERT(!IsEmpty()); } // should be able to get out everything we put in for (i = 0; i < numEntries; i++) { ASSERT(Remove(getKey(p[i])) == p[i]); } ASSERT(IsEmpty()); SanityCheck();}//----------------------------------------------------------------------// HashIterator<Key,T>::HashIterator// Initialize a data structure to allow us to step through// every entry in a has table.//----------------------------------------------------------------------template <class Key, class T>HashIterator<Key,T>::HashIterator(HashTable<Key,T> *tbl) { table = tbl; bucket = table->FindNextFullBucket(0); bucketIter = NULL; if (bucket < table->numBuckets) { bucketIter = new ListIterator<T>(table->buckets[bucket]); }}//----------------------------------------------------------------------// HashIterator<Key,T>::Next// Update iterator to point to the next item in the table.//----------------------------------------------------------------------template <class Key,class T>voidHashIterator<Key,T>::Next() { bucketIter->Next(); if (bucketIter->IsDone()) { delete bucketIter; bucketIter = NULL; bucket = table->FindNextFullBucket(++bucket); if (bucket < table->numBuckets) { bucketIter = new ListIterator<T>(table->buckets[bucket]); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -