哈希表>
哈希表也叫散列表,是依據關鍵碼值(key value)而直接進行訪問的數據結構.也就是說,它通過把關鍵碼值映射到表中的一個位置來訪問記錄,以加快查找的速度.這個映射函數叫做散列函數,存放記錄的數組叫散列表.
瞭解了什仫是哈希表之後,我們發現哈希表這種數據結構是類似於線性表的,只是表中的元素不是精密排列的,而是可能存在空間.
比如我們存儲70個元素,但是我們可能爲這70個空間申請了100個元素的
空間,70/100=0.7,這個數字稱爲負載因子(有的書中也叫載荷因子),x(負載因子)=填入表中的元素個數/散列表的長度,之所以存在負載因子是爲了"高速存取"的目的.我們基於一種結果儘可能的隨機平均分佈的固定函數H爲每一個元素安排存儲位置,這樣就能夠避免遍歷性質的線性搜索,以達到高速存取,但是這個結果是隨機的,也必定導致衝突.
哈希衝突/哈希碰撞>
不同的key值經過哈希函數處理後可能產生相同的值哈希地址,這種情況就叫做哈希衝突,任意的散列函數都不能避免哈希衝突.
如何解決哈希衝突的情況呢?閉散列方法(開放定址法).,開鏈法/拉鍊法(哈希桶)
一.閉散列方法(開放定址法)>
1).線性探測>
2).二次探測>
3).雙散列方法>
顧名思義雙散列就是有兩個散列地址,用第一個哈希函數解決不了衝突域時,用第二個繼續計算,只到衝突域解決爲止.雙散列法優於二次探測法
二.開鏈法/拉鍊法(哈希桶)
對關鍵碼集合用一個散列函數計算他們存放的位置.將散列表地址相同的元素放到一個集合中,用鏈表鏈接起來.
在我的代碼實現中用到的解決哈希衝突的方法是閉散列中的線性探測法和拉鍊法,值得注意的是:降低哈希衝突最好使用素數做哈希表的容量(用素數做除數可以減少哈希衝突).
構造散列函數的方法>
1).直接尋址法>
取關鍵字或關鍵字的某個線性函數值爲散列地址.H(key)=key或H(key)=a*key+b,其中a,b爲常數(這種散列函數叫做自身函數).若其中H(key)中已經存在數據,就往下一個找,直到H(key)中沒有值了,就放進去.
2).除留餘數法>
取key被不大於散列表表長m的數p除後所得的餘數爲散列地址.Hash(key)=key%p;
3).數字分析法
4).平方取中法
5).摺疊法
6).隨機數法
更詳細的介紹見>http://url.cn/416R94i
解決哈希衝突的閉散列法
namespace HashTable
{
enum Status
{
EMPTY,
EXIST,
DELECT,
};
template<class K,class V>
struct HashNode
{
K _key;
V _value;
Status _status;
HashNode(const K& key=K(),const V& value=V())
:_key(key)
,_value(value)
,_status(EMPTY)
{}
};
template<class K>
struct __HashFunc
{
size_t operator()(const K& key)
{
return key;
}
};
//特化
template<>
struct __HashFunc<string>
{
static size_t BKDRHash(const char*str)
{
unsigned int seed= 131;// 31 131 1313 13131 131313
unsigned int hash= 0;
while(*str)
{
hash = hash * seed + (*str++);
}
return(hash& 0x7FFFFFFF);
}
size_t operator()(const string& str)
{
return BKDRHash(str.c_str());
}
};
template<class K,class V,class HashFunc=__HashFunc<K>>
class HashTables
{
typedef HashNode<K,V> Node;
public:
HashTables()
:_size(0)
{
_tables.resize(_GetPrime(0));
}
HashTables(const HashTables<K,V,HashFunc>& hash)
{
size_t size=hash._tables.size();
_tables.resize(size);
for (size_t i=0;i<_tables.size();++i)
{
if (hash._tables[i]._status == EXIST)
{
_tables[i]._key=hash._tables[i]._key;
_tables[i]._value=hash._tables[i]._value;
_tables[i]._status=hash._tables[i]._status;
}
}
_size=hash._size;
}
HashTables<K,V,HashFunc>& operator=(const HashTables<K,V,HashFunc>& hash)
{
if (this != &hash)
{
HashTables<K,V,HashFunc> tmp(hash);
_Swap(tmp);
}
return *this;
}
public:
bool Insert(const K& key,const V& value)
{
_CheckSize();
size_t index=_GetPosition(key);
while (_tables[index]._status == EXIST)
{
if (_tables[index]._key == key)
{
_tables[index]._value++;
_size++;
return false;
}
++index;
if(index == _tables.size())
index=0;
}
_tables[index]._key=key;
_tables[index]._value=value;
_tables[index]._status=EXIST;
_size++;
return true;
}
void Delete(const K& key) //僞刪除法
{
Node *ret=Find(key);
if (ret != NULL)
{
ret->_status=DELECT;
_size--;
}
}
Node *Find(const K& key)
{
size_t index=_GetPosition(key);
size_t src=index;
while (_tables[index]._status != EMPTY)
{
if (_tables[index]._key == key)
{
if (_tables[index]._status == DELECT)
return NULL;
else
return &_tables[index];
}
++index;
if(index == src)
break;
}
return NULL;
}
void Display()
{
for (size_t i=0;i<_tables.size();++i)
{
if (_tables[i]._status == EXIST)
{
cout<<_tables[i]._key<<" ";
}
}
cout<<endl;
}
protected:
void _CheckSize()
{
if (_tables.size() == 0 || _size*10/_tables.size() >= 8)
{
size_t NewSize=_GetPrime(_tables.size());
HashTables<K,V,HashFunc> hashTable; //現代的寫法
hashTable._tables.resize(NewSize);
for (size_t i=0;i<_tables.size();++i)
{
if(_tables[i]._status == EXIST)
{
hashTable.Insert(_tables[i]._key,_tables[i]._value);
}
}
_Swap(hashTable);
}
}
void _Swap(HashTables<K,V,HashFunc> hash)
{
_tables.swap(hash._tables);
swap(_size,hash._size);
}
size_t _GetPrime(size_t num)
{
const int _PrimeSize= 28;
//素數表
static const unsigned long _PrimeList[_PrimeSize] =
{
53ul, 97ul, 193ul, 389ul, 769ul,
1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
49157ul, 98317ul, 196613ul, 393241ul,
786433ul,
1572869ul, 3145739ul, 6291469ul, 12582917ul,
25165843ul,
50331653ul, 100663319ul, 201326611ul, 402653189ul,
805306457ul,
1610612741ul, 3221225473ul, 4294967291ul
};
for (size_t i=0;i<_PrimeSize;++i)
{
if(_PrimeList[i] > num)
return _PrimeList[i];
else
continue;
}
return _PrimeList[_PrimeSize-1];
}
size_t _GetPosition(const K& key) //除留餘數法
{
HashFunc hf;
return hf(key)%_tables.size();
}
protected:
vector<Node> _tables;
size_t _size;
};
}
解決哈希衝突的拉鍊法>
namespace HashTable_List
{
template<class K,class V>
struct HashNode
{
K _key;
V _value;
HashNode<K,V> *_next;
HashNode(const K& key=K(),const V& value=V())
:_key(key)
,_value(value)
,_next(NULL)
{}
};
template<class K>
struct __HashFunc
{
size_t operator()(const K& key)
{
return key;
}
};
//偏特化
template<>
struct __HashFunc<string>
{
static size_t BKDRHash(const char*str)
{
unsigned int seed= 131;// 31 131 1313 13131 131313
unsigned int hash= 0;
while(*str)
{
hash = hash * seed + (*str++);
}
return(hash& 0x7FFFFFFF);
}
size_t operator()(const string& str)
{
return BKDRHash(str.c_str());
}
};
template<class K,class V,class HashFunc=__HashFunc<K>>
class HashTable
{
typedef HashNode<K,V> Node;
public:
HashTable()
:_size(0)
{}
HashTable(const HashTable<K,V,HashFunc>& hash)
{
_table.resize(hash._table.size());
for (size_t i=0;i<hash._table.size();++i)
{
Node *cur=_table[i];
while (cur)
{
Insert(cur->_key,cur->_value);
cur=cur->_next;
}
}
}
HashTable<K,V,HashFunc>& operator=(const HashTable<K,V,HashFunc>& hash)
{
if (this != &hash)
{
HashTable<K,V,HashFunc> tmp(hash);
_Swap(hash);
}
return *this;
}
~HashTable()
{
for (size_t i=0;i<_table.size();++i)
{
Node *cur=_table[i];
Node *del=NULL;
while (cur)
{
del=cur;
cur=cur->_next;
delete del;
del=NULL;
}
}
_size=0;
_table.clear();
}
public:
Node *Find(const K& key)
{
int index=_GetPosition(key,_table.size());
Node *cur=_table[index];
while (cur)
{
if(cur->_key == key)
{
return cur;
}
cur=cur->_next;
}
return NULL;
}
bool Insert(const K& key,const V& value)
{
//頭插
_CheckSize();
size_t index=_GetPosition(key,_table.size());
Node *ret=Find(key);
if(ret) //插入的元素已經存在
{
ret->_value++;
_size++;
return false;
}
Node *NewNode=new Node(key,value);
NewNode->_next=_table[index];
_table[index]=NewNode;
_size++;
return true;
}
bool Remove(const K& key)
{
Node *prev=NULL;
int index=_GetPosition(key,_table.size());
Node *cur=_table[index];
while (cur)
{
if(cur->_key == key)
{
if (prev == NULL) //刪除的是第一個結點
_table[index]=cur->_next;
else //刪除尾結點,刪除中間節點
prev->_next=cur->_next;
delete cur;
cur=NULL;
_size--;
return true;
}
prev=cur;
cur=cur->_next;
}
return false;
}
void Display()
{
for (size_t i=0;i<_table.size();++i)
{
Node *cur=_table[i];
cout<<i<<":";
while (cur)
{
cout<<cur->_key<<" ";
cur=cur->_next;
}
cout<<endl;
}
}
protected:
size_t _GetPrime(size_t num)
{
const int _PrimeSize= 28;
//素數表
static const unsigned long _PrimeList[_PrimeSize] =
{
53ul, 97ul, 193ul, 389ul, 769ul,
1543ul, 3079ul, 6151ul, 12289ul, 24593ul,
49157ul, 98317ul, 196613ul, 393241ul,
786433ul,
1572869ul, 3145739ul, 6291469ul, 12582917ul,
25165843ul,
50331653ul, 100663319ul, 201326611ul, 402653189ul,
805306457ul,
1610612741ul, 3221225473ul, 4294967291ul
};
for (size_t i=0;i<_PrimeSize;++i)
{
if(_PrimeList[i] > num)
return _PrimeList[i];
else
continue;
}
return _PrimeList[_PrimeSize-1];
}
void _CheckSize()
{
if (_size == 0 || _size == _table.size())
{
vector<Node *> tmp;
tmp.resize(_GetPrime(_table.size()));
for (size_t i=0;i<_table.size();++i)
{
Node *cur=_table[i];
while (cur)
{
Node *next=cur->_next;
size_t index=_GetPosition(cur->_key,tmp.size());
cur->_next=tmp[index];
tmp[index]=cur;
cur=next;
}
}
tmp.swap(_table);
}
}
void _Swap(HashTable<K,V,HashFunc> hash)
{
_table.swap(hash._table);
swap(_size,hash._size);
}
size_t _GetPosition(const K& key,size_t size)
{
HashFunc hf;
return hf(key)%size;
}
protected:
vector<Node *> _table;
size_t _size;
};
}