哈希表
(Hash table,也叫散列表),是根据关键码值(Key value)而直接进行访问的
数据结构
。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做
散列函数
,存放记录的
数组
叫做
散列表
。
enum Status //判断表中选中位置是否为空
{
EMPTY,
EXIST,
DELETE
};
template<class K,class V>
struct HashNode
{
K _key;
V _value;
Status _sta;
HashNode(const K& key=K(),const V& value=V())
:_key(key)
,_value(value)
,_sta(EMPTY)
{}
};
template<class K,class V>
class HashTable
{
public:
typedef HashNode<K,V> Node;
Checksize();
size_t index=HashFunc(key);
while(_table[index]._sta==EXIST)
{
if(_table[index]._key==key)
return false;
if(_table.empty)
return NULL;
for(size_t i=0;i<_table.size();i++)
{
return NULL;
}
for(size_t i=0;i<_table.size();i++)
{
cout<<_table[i]._key<<" ";
}
cout<< endl;
}
protected:
size_t HashFunc(const K& key) //hash函数
{
return key%_table.size();
void Checksize() //判断存储空间
{
if(_table.size()==0||_size*10/_table.size()>=8)
{
size_t newsize=GetNextPrime(_table.size());
HashTable hash;
hash._table.resize(newsize);
for(size_t i=0;i<_table.size();i++)
{
if(_table[i]._sta==EXIST)
{
hash.Insert(_table[i]._key,_table[i]._value);
}
}
this->Swap(hash);
}
}
给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数。
寻址方法:
1.
直接寻址
法
:取关键字或关键字的某个线性函数值为散列地址。即H(key)=key或H(key) = a·key + b,其中a和b为常数(这种
散列函数
叫做自身函数)。若其中H(key)中已经有值了,就往下一个找,直到H(key)中没有值了,就放进去。
2
. 除留余数法:取关键值被某个不大于散列表长m的数p除后的所得的余数为散列地址。Hash(Key)= Key % P。
3. 平方取中法:
当无法确定关键字中哪几位分布较均匀时,可以先求出关键字的平方值,然后按需要取平方值的中间几位作为哈希地址。这是因为:平方后中间几位和关键字中每一位都相关,故不同关键字会以较高的概率产生不同的哈希地址。
哈希冲突/哈希碰撞
不同的Key值经过哈希函数Hash(Key)处理以后可能产生相同的值哈希地址,我们称这种情况为哈希冲突。任意的散列函数都不能避免产 生冲突。
不同的Key值经过哈希函数Hash(Key)处理以后可能产生相同的值哈希地址,我们称这种情况为哈希冲突。任意的散列函数都不能避免产 生冲突。
哈希表在查找过程中,关键码的比较次数,取决于产生冲突的多少,产生的冲突少,查找效率就高,产生的冲突多,查找效率就低。因此,影响产生冲突多少的因素,也就是影响查找效率的因素。影响产生冲突多少有以下三个因素:
2. 处理冲突的方法;
散列表
的载荷因子定义为:α= 填入表中的元素个数 / 散列表的长度
α是
散列表
装满程度的标志因子。由于表长是定值,α与“填入表中的元素个数”成正比,所以,α越大,填入表中的元素较多,产生冲突的可能性就越大;α越小,填入表中的元素较少,产生冲突的可能性就越小。对于开放定址法,载荷因子应该严格控制在0.7-0.8之间,超过0.8时,cpu的缓存不命中率会曲线上升
#include<iostream>
#include<vector>
using namespace std;
#include<vector>
using namespace std;
enum Status //判断表中选中位置是否为空
{
EMPTY,
EXIST,
DELETE
};
template<class K,class V>
struct HashNode
{
K _key;
V _value;
Status _sta;
HashNode(const K& key=K(),const V& value=V())
:_key(key)
,_value(value)
,_sta(EMPTY)
{}
};
template<class K,class V>
class HashTable
{
public:
typedef HashNode<K,V> Node;
HashTable()
:_size(0)
{
:_size(0)
{
_table.resize(GetNextPrime(0));
}
}
bool Insert(const K& key,const V& value)
{
{
Checksize();
size_t index=HashFunc(key);
while(_table[index]._sta==EXIST)
{
if(_table[index]._key==key)
return false;
++index;
if(index==_table.size())
index=0;
}
_table[index]._key=key;
_table[index]._value=value;
_table[index]._sta=EXIST;
_size++;
return true;
if(index==_table.size())
index=0;
}
_table[index]._key=key;
_table[index]._value=value;
_table[index]._sta=EXIST;
_size++;
return true;
}
Node* Find(const K& key)
{
{
if(_table.empty)
return NULL;
for(size_t i=0;i<_table.size();i++)
{
if(_table[i]._sta==EXIST && _table[i]._key==key)
{
return &_table[i];
}
else
continue;
}
{
return &_table[i];
}
else
continue;
}
return NULL;
}
void Display()
{
{
if(_table.size()==0)
return;
return;
for(size_t i=0;i<_table.size();i++)
{
cout<<_table[i]._key<<" ";
}
cout<< endl;
}
protected:
size_t HashFunc(const K& key) //hash函数
{
return key%_table.size();
}
void Checksize() //判断存储空间
{
if(_table.size()==0||_size*10/_table.size()>=8)
{
size_t newsize=GetNextPrime(_table.size());
HashTable hash;
hash._table.resize(newsize);
for(size_t i=0;i<_table.size();i++)
{
if(_table[i]._sta==EXIST)
{
hash.Insert(_table[i]._key,_table[i]._value);
}
}
this->Swap(hash);
}
}
size_t GetNextPrime(size_t num) //增容素数数列(使用素数做除数可以减少哈希冲突),素数表对齐做哈希表的容量,降低哈希冲突
{
long long PrimeSize[28]={53,97,193,389,769,1543,3079,
6151,12289,24593,49157,98317,196613,393241,786433ul,
1572869ul,3145739,6291469,12582917,25165843,50331653,
100663319,201326611,402653189,805306457,1610612741,
3221225473,4294967291};
for(size_t i=0;i<28;i++)
{
if(PrimeSize[i]>num)
{
return PrimeSize[i];
}
else
continue;
}
{
long long PrimeSize[28]={53,97,193,389,769,1543,3079,
6151,12289,24593,49157,98317,196613,393241,786433ul,
1572869ul,3145739,6291469,12582917,25165843,50331653,
100663319,201326611,402653189,805306457,1610612741,
3221225473,4294967291};
for(size_t i=0;i<28;i++)
{
if(PrimeSize[i]>num)
{
return PrimeSize[i];
}
else
continue;
}
return 4294967291; //返回最大容量约为4G
}
void Swap(HashTable<K,V>& hs)
{
_table.swap(hs._table);
swap(_size,hs._size);
}
{
_table.swap(hs._table);
swap(_size,hs._size);
}
private:
vector<Node> _table;
size_t _size;
};
vector<Node> _table;
size_t _size;
};
#include"HashTable.h"
#include<cstdlib>
void TestHashTable()
{
int a[40]={1,2,3,4,5,6,7,8,9,10
,11,12,13,14,15,16,17,18,19,20,
21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40};
HashTable<int,int> ht;
for(int j=0;j<40;j++)
{
ht.Insert(a[j],j);
}
ht.Display();
#include<cstdlib>
void TestHashTable()
{
int a[40]={1,2,3,4,5,6,7,8,9,10
,11,12,13,14,15,16,17,18,19,20,
21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40};
HashTable<int,int> ht;
for(int j=0;j<40;j++)
{
ht.Insert(a[j],j);
}
ht.Display();
}
int main()
{
TestHashTable();
system("pause");
return 0;
}
int main()
{
TestHashTable();
system("pause");
return 0;
}