/*
hash在实际工程里是用的很多的,主要是hash提供了O(1)常量的存储和查找时间
那如何自己设计一个hash需要考虑哪些方面了?
hash有2种实现方式,一种是链式的hash,还有一种是开地址hash方面
下面来看看开地址hash如何实现
负载因子 a = n/m n为元素个数 m为槽个数
在链式hash里a表示在均匀散列的情况下,每个槽存放元素个数,也就是平均找出次数
在开地址hash负载因子a必须少于1,应该n必须小于m。
开地址hash负载因子和平均查找次数关系为
p= 1 /(1-a)
假设 a=0.5 p=2 表示查找一个元素平均为2次
a=0.8 p=5 表示查找一个元素平均为5次
a=0.95 p=20 表示查找一个元素平均为20次
可以看出 a越接近1 p越大。所以一般呀保证a<0.5
哈希函数的选择
h(k)=x
k为key可以为int或者string类型
m为槽的大小,m必须素数,在就是考虑实际需要多少空间 比如可能有2000个元素,可以选择m=1699
这样负载因子a=2000/1699=1.17比较合适
通常的哈希函数使用取模法 h(k)=k % m
使用双散列哈希较少冲突 h(k,i)=(k % m + (i +(k % m1))) % m //m1选择一个比m略少的值 比如m1=m-3
*/
template<class T>
struct CHashPair
{
T m_data;
int key;
CHashPair()
{
key = 0;
}
CHashPair(const CHashPair& from)
{
if (this == &from)
{
return *this;
}
m_data = from.m_data;
key = from.key;
}
};
template<class T,int size>
class CHash
{
public:
CHash(){}
void Init()
{
for (int i=0;i<m_size;++i)
{
mb[i].key = 0;
}
}
T* Find(int key)
{
for (int i=0;i<m_size;++i)
{
int h = HashFunction(key,i);
CHashPair<T>& Pair = mb[h];
if (Pair.key == key)
{
return &Pair.m_data;
}
return NULL;
}
return 0;
}
bool Insert(const CHashPair<T>& Pair)
{
T* data = Find(Pair.key);
if (0 != data)
{
return false;
}
for (int i=0;i<size;++i)
{
int h = HashFunction(Pair.key,i);
CHashPair<T>& Pa = mb[h];
if (0 == Pa.key)
{
Pa.key = Pair.key;
Pa.m_data = Pair.m_data;
break;
}
}
return true;
}
void Remove(int key)
{
T* data = Find(key);
if (0 != data)
{
return;
}
for (int i=0;i<size;++i)
{
int h = HashFunction(key,i);
CHashPair<T>& Pa = mb[h];
if (key== Pa.key)
{
Pa.key = 0;
break;
}
}
}
private:
int HashFunction(int key,int i)
{
int h = 0;
h = (key % size + (i + (key % size - 3))) % size;
return h;
}
private:
int m_size;
CHashPair<T> mb[size];
};
int _tmain(int argc, _TCHAR* argv[])
{
CHash<int,1699> hash;
CHashPair<int> Pair;
Pair.key = 1005;
Pair.m_data = 10;
hash.Insert(Pair);
int* value = hash.Find(1005);
}