哈希表又称散列表,是一种通过键值映射到值的数据结构,具有查找快速的优点。
哈希表的基本思想是:
14 |
23 9 |
|
39 25 11 |
|
|
首先我们观察一下上图用常规拉链法所造出的哈希表,它有13个由头结点组成的数组,以及和关键词序列数目相同的节点,那么我们不妨创建一个由13个加与关键词序列数目的数组,其中hash节点定义如下:
struct hashNode
{
int key;//键值
int value;//值
int postion;//指示位置
};
其中postion用来存放数组下标,然后所定义的数组可以如下:hashNode hashTable[24];//大小应定为所插入元素个数的2倍
其中前13个类比哈希表的头结点数组,后11个存放数据,然后将其全部节点的postion值都定义为-1,表示其中还没有存入数据:memset(hashTable,-1,sizeof (hashTable));//偷了个懒
然后我们构造哈希函数:int hashf(int key)//hash函数
{
return key%11;
}
并且我们定义一个辅助变量cnt,将其初始化为第一个存放数据的数组下标,现在是13;int cnt=13;
当我们插入数据时我们先计算出它的hash值,比如第一个键值19,它的hash值是19%11=8,那么我们查找哈希表的第8个节点,发现它的postion值为-1,表明这个hash值还未插入数据,然后我们令这个节点的postion值等于此时的cnt值,再在cnt这个节点中装入hash节点,再让cnt++,这就是插入第一个未查找过的hash值的方法。那么如果这个hash值不是第一次被访问,比如我再插入一个关键词为8的哈希节点,那么我们可以通过一个while循环,找到第一个表中节点postion值不为-1的点,再重复插入操作,其代码如下,其中hashlen值是构造hash函数用的:void hash_insert(int key,int value,int hashlen,int &cnt)
{
int pos=hashf(key,hashlen);
while (hashTable[pos].postion!=-1)//当pos位上的hash表已经存储了位置时,找到没有存储位置的hash表
{
pos=hashTable[pos].postion;
}
hashTable[pos].postion=cnt;
hashTable[cnt].key=key;//cnt为用于存储hash节点最近的空节点的下标
hashTable[cnt].value=value;
cnt++;
}
那么我们现在构建好了哈希表,下一步就是根据键值查找hash元素,我们可以先通过算出hash函数,然后对其节点开始遍历,当该节点还有下一个指向的节点时,不断的进行循环,除非该节点就是我们所需寻找的节点,其中有一个注意点,那就是头结点的那个节点不应拿来比较键值是否相等,代码如下:int hash_search(int key,int hashlen)
{
int pos=hashf(key,hashlen);
while (hashTable[pos].postion!=-1)//pos>=hashlen是因为hash表的前len个节点只存放位置,不存放数据
{
if (key==hashTable[pos].key&&pos>=hashlen)
return hashTable[pos].value;
else
pos=hashTable[pos].postion;
}
if (key==hashTable[pos].key&&pos>=hashlen)
return hashTable[pos].value;
printf("无法找到\n");
return 0x3f3f3f3f;
}
至于哈希节点的删除,这件事就交给机智的你来完成了……总的代码:
//类似于hash表的拉链法实现
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct hashNode
{
int key;//键值
int value;//值
int postion;//指示位置
};
hashNode hashTable[1000];//大小为hashlen的2倍即可
int hashf(int key,int hashlen)//hash函数
{
return key%hashlen;
}
void hash_insert(int key,int value,int hashlen,int &cnt)
{
int pos=hashf(key,hashlen);
while (hashTable[pos].postion!=-1)//当pos位上的hash表已经存储了位置时,找到没有存储位置的hash表
{
pos=hashTable[pos].postion;
}
hashTable[pos].postion=cnt;
hashTable[cnt].key=key;//cnt为用于存储hash节点最近的空节点的下标
hashTable[cnt].value=value;
cnt++;
}
int hash_search(int key,int hashlen)
{
int pos=hashf(key,hashlen);
while (hashTable[pos].postion!=-1)//pos>=hashlen是因为hash表的前len个节点只存放位置,不存放数据
{
if (key==hashTable[pos].key&&pos>=hashlen)
return hashTable[pos].value;
else
pos=hashTable[pos].postion;
}
if (key==hashTable[pos].key&&pos>=hashlen)
return hashTable[pos].value;
printf("无法找到\n");
return 0x3f3f3f3f;
}
int main()
{
memset(hashTable,-1,sizeof (hashTable));
int hashlen=10,cnt=hashlen;//hashlen大小为所需插入元素个数
int key[10]= {2,3,1,4,13,21,31,10,11,19};
int value[10]= {4,2,6,10,37,72,17,3,92,11};
for (int i=0;i<=9;i++)
{
hash_insert(key[i],value[i],hashlen,cnt);//cnt与链式前向星的思路有点类似
}
for (int i=9;i>=0;i--)
{
int temp=hash_search(key[i],hashlen);
printf("%d ",temp);
}
return 0;
}