散列表
散列表(Hash table,也叫哈希表),是根据键(Key)而直接访问在内存储存位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射函数称做散列函数,存放记录的数组称做散列表。
来源:维基百科
4.1定义
作用:不进行比较就能一步到位地查找到指定的元素
将在结构的元素存储位置和元素值之间建立一种映射关系
称上面这种关系为哈希函数f,称元素值为关键字
关系f的作用就是使每一个关键字与表中的一个元素的存储位置相对应
4.2散列函数
将关键字映射为散列表中适当位置的函数
通过散列函数计算出的元素的存储地址称为散列地址
构建散列表的关键就是设计一个好的散列函数
什么是好的散列函数?
需要具有两个特点:冲突少+均匀
冲突:
是指两个不同的关键字经过散列函数映射到了同一个地址(value1!=value2 but f(value1)=f(value2)) 是我们在建造散列函数需要避免的情况(尽量)
均匀:
如果对关键字集合中的任何一个关键字 通过散列函数映射到地址集合的任何一个地址的概率是相等的------->这个函数是均匀的
4.2.1直接定址法
取关键字的某个线性函数为散列函数
4.2.2除留余数法
不需要已知关键字集合
比较常用的构造散列函数
4.2.3平方取中法
将关键字平方后,根据散列表的设计大小,取平方结果的中间若干位作为散列地址,较为常用
例如 如果散列地址取2位,则345的散列地址为:
4.3基于散列的查找
散列表在查找的时候有个很大的缺点——冲突
如何处理冲突
4.3.1开放定址法
在数据存取的时候 发生冲突后 就寻找下一个空白的散列地址
4.3.2链地址法
将所有具有相同散列地址的不同关键字存放在一个单链表中(同义词子表),散列表中存放在一个单链表中
4.3.3公共溢出区法
将散列表分为基本表和溢出表两部分,两部分大小相同
将发生冲突的关键字存放在溢出表
查找时,对给定的关键字计算散列表地址,然后与基本表中相应位置的元素进行比较 如果一致查找成功 如果不一致 到溢出表中查找
template<typename DataType>class HashTable
{
public:
HashTable(int size)
{
maxSize = size;
count = 0;
elements = new DataType[size];
if(elements==NULL)
exit(1);
for (int i=0;i<size;i++)
elements[i]=NULL;
}
~HashTable()
{
delete elements;
}
//散列函数——除留余数法 p为根据关键字集合设定的值
int hash(DataType value, int p)
{
return value%p;
}
//查找函数, 返回所查找元素的地址
int searchHash(DataType value)
{
int p = hash(value);
if (elements[p]==value)
return p;
int rp=(p+1)%maxSize;
while(rp!=p)
{
if(elements[rp]==value)
return rp;
if(elements[rp]==NULL)
break;
rp=(rp+1)%maxSize;
}
if(rp==p)
return -1;
else
{
elements[rp]=value;
return rp;
}
}
private:
int maxSize;
int count;
DataType *elements;
};
参考书籍《妙趣横生的算法(C++语言实现)》