散列

選擇鍵值,衝突的時候採起不一樣的策略函數

散列函數:this

簡單的散列函數:spa

1 int hash(const string & key,int tableSize) 2 { 3     int hashVal = 0; 4     for(int i = 0; i < key.length();++i) 5  { 6         hashVal + = key[i]; 7  } 8     return hashVal % tableSize; 9 }

比較好的散列函數:code

 1 int hash( const string & key,int tableSize )  2 {  3     int hashVal = 0;  4     for(int i = 0; i <key.length();++i)  5  {  6         hashVal = 37*hashVal + key[i];  7  }  8     hashVal %= tableSize;  9     if(hashVal < 0) 10         hashVal +=tableSize; 11 
12     return hashVal; 13 }

鍵的長度和性質 影響選擇。blog

分離連接法接口

分離連接散列表的類構架ci

 1 template <typename HashedObj>
 2 class HashTable  3 {  4 public:  5     explicit HashTable( int size = 101);  6     bool contains (const HashedObj & x) const;  7     void makeEmpty();  8     void insert(const HashedObj & x);  9     void remove(const HashedObj & x); 10 private: 11     vector<list<HashedObj> > theLists; 12     int currentSize; 13     void rehash(); 14     int myhash( const HashedObj & x) const; 15 }; 16 int hash(const string & key); 17 int hash(int key);

散列表myhash的成員函數:element

1 int myhash(const HashedObj & x) const
2 { 3     int hashVal = hash(x); 4     hashVal %= theLists.size(); 5     if(hashVal < 0) 6         hashVal += theLists.size(); 7     return hashVal; 8 }

使用name成員爲鍵,提供的散列函數實例:rem

 1 class Employee  2 {  3 public:  4     const string & getName() const
 5  {  6         return name;  7  }  8     bool operator==( const Employee & rhs ) const
 9  { 10         return getName() == rhs.getName(); 11  } 12     bool operator!=(const Employee & rhs) const
13  { 14         return !(*this == rhs); 15  } 16 private: 17     string name; 18     double salary; 19     int seniority; 20 }; 21 int hash(const Employee & item) 22 { 23     return hash(item.getName()); 24 }

實現makeEmpty contains remove:get

 1 void makeEmpty()  2 {  3     for(int i =0;i<theLists.size();i++)  4  theLists[i].clear();  5 }  6 bool contains(const HashedObj & x) const
 7 {  8     const list<HashedObj> & whichList = theLists[myhash(x)];  9     return find(whichList.begin(),whichList.end(),x)!=whichList.end(); 10 } 11 bool remove(const HashedObj & x) const
12 { 13     list<HashedObj> & whichList = theLists[myhash(x)]; 14     list<HashedObj>::iterator itr = find(whichList.begin(),whichList.end(),x); 15 
16     if(itr == whichList.end()) 17         return false; 18     
19  whichList.erase(itr); 20     --currentSize; 21     return true; 22 }

分離散列表的insert實例

 1 bool insert(const HashedObj & x)  2 {  3     list<HashedObj> & whichList = theLists[myhash(x)];  4     if(find(whichList.begin(),whichList.end(),x)!=whichList.end())  5         return false;  6  whichList.push_back(x);  7     if(++currentSize > theLists.size())  8  rehash();  9 
10     return true; 11 }

裝填因子:散列表中的元素個數 與 散列表大小的 比值

執行一次查找所需的時間:計算散列函數值所須要的常數時間加上遍歷表所用的時間

不使用鏈表的散列表:

當衝突發生時,直接尋找下一單元

<線性探測>

<平方探測>

使用探測策略的散列表的類接口

 1 template <typename HashedObj>
 2 class HashedObj  3 {  4 public:  5     explicit HashTable(int size = 101);  6     bool contains(const HashedObj & x) const;  7     void makeEmpty();  8     bool insert(const HashedObj & x);  9     bool remove(const HashedObj & x); 10     enum EntryType{ACTIVE,EMPTY,DELETED}; 11 private: 12     struct HashEntry 13  { 14  HashedObj element; 15  EntryType info; 16 
17         HashEntry(const HashedObj & e = HashedObj(),EntryType i = EMPTY):element(e),info(i){} 18  }; 19     vector<HashEntry> array; 20     int currentSize; 21     bool isActive(int currentPos) const; 22     int findPos(const HashedObj & x) const; 23     void rehash(); 24     int myhash(const HashedObj & x) const; 25 };

初始化平方探測散列表

 1 explicit HashTable(int size = 101):array(nextPrime(size))  2 {  3  makeEmpty();  4 }  5 void makeEmpty()  6 {  7     currentSize = 0;  8     for(int i = 0 ; i < array.size(); i++)  9         array[i].info = EMPTY; 10 }

使用平方探測進行散列的contains findPos isActive

 1 bool contains(const HashedObj & x) const
 2 {  3     return isActive(findPos(x));  4 }  5 int findPos(const HashedObj & x) const
 6 {  7     int offset = 1;  8     int currentPos = myhash(x);  9 
10     while(array[currentPos].info != EMPTY && array[currentPos].element != x) 11  { 12         currentPos += offset; 13         offset += 2; 14         if(currentPos >= array.size()) 15             currentPos -= array.size(); 16  } 17     return currentPos; 18 } 19 bool isActive(int currentPos) const
20 { 21     return array[currentPos].info == ACTIVE; 22 }

使用平方探測的insert remove

bool insert( const HashedObj & x) { int currentPos = findPos(x); if(isActive( currentPos )) return false; array[currentPos] = HashEntry(x,ACTIVE); if(++currnetSize>array.size()/2) rehash(); } bool remove(const HashedObj & x) { int currentPos = findPos(x); if(!isActive(currentPos)) return false; array[currentPos].info = DELETED; return true; }

<雙散列>

對分離散列表的再散列

 1 void rehash()  2 {  3     vector<HashEntry> oldArray = array;  4     array.size(nextPrime(2*oldArray.size()));  5     for(int j = 0; j < array.size(); j++)  6  {  7         array[j].info = EMPTY;  8  }  9     currentSize = 0; 10     for(int i = 0; i < array.size(); i++) 11  { 12         if(oldArray[i].info == ACTIVE) 13  insert(oldArray[i].element); 14  } 15 }

對探測散列表的再散列

 1 void rehash()  2 {  3     vector<list<HashedObj> > oldLists = theLists;  4     theLists.resize( nextPrime( 2*theLists.size() ) );  5     for(int j = 0; j < theLists.size(); j++)  6  {  7  theLists[j].clear();  8  }  9     currentSize = 0; 10     for(int i = 0; i < oldLists.size(); i++) 11  { 12         list<HashedObj>::iterator itr = oldLists[i].begin(); 13         while( itr != oldLists[i].end( ) ) 14             insert(*itr++); 15  } 16 }
相關文章
相關標籤/搜索