HashTable的拉链法的数组实现
来源:互联网 发布:台湾ptt大陆网络用语 编辑:程序博客网 时间:2024/04/28 08:41
哈希表又称散列表,是一种通过键值映射到值的数据结构,具有查找快速的优点。
哈希表的基本思想是:
1.以结点的关键字k为自变量,通过一个确定的哈希函数H,计算出对应的函数值H(k),作为结点的存储位置并将结点存入。
2.顺序查找、折半查找、树的查找是建立在比较基础上的查找,而哈希表的查找是直接查找。
但是对于一个确定的哈希函数H,其对于所需存储数据计算所得的H(K)可能是相同的,这就是哈希表的冲突,即若某个哈希函数H对于不同的关键字得到相同的哈希地址,称为冲突。
冲突举例:
比如对于已有关键词序列(14,23,39,9,25,11),构造hash函数H为H(K)=K mod 7,通过hash函数建立含6个元素的hash表,如下:
14
23
9
39
25
11
其中23和9,39和25以及11冲突,应对这种冲突,哈希表有多个处理方法,比如开放定址法,拉链法,再哈希法……,这里介绍的是拉链法。
我们先来看看常规的拉链法,常规的拉链法可以理解为数组与多个单链表的结合,有点类似图中的邻接表。它是将所有哈希函数值相同的结点链接在同一个单链表中。若哈希函数的值域为0到m-1,将散列表定义为一个由m个头指针组成的指针数组HT[m],凡是散列地址为i的结点,均插入到以HT[i]为头指针的单链表中。
例如给出关键词序列(19,14,23,01,68,20,84,27,55,11,10),hash函数为H(K)=K%13,其构造的拉链法hash表如下图:
其中哈希表的数据只存在其指针数组所引出的单链表中。
我要讲的哈希表的数组实现也是基于拉链法,但是它是不创建单链表的,即所有的数据都存在一个数组中,它的思想类似图的存储结构中的链式前向星,不懂链式前向星的可以自行百度,但是对本文没有阅读障碍。
首先我们观察一下上图用常规拉链法所造出的哈希表,它有13个由头结点组成的数组,以及和关键词序列数目相同的节点,那么我们不妨创建一个由13个加与关键词序列数目的数组,其中hash节点定义如下:
总的代码:
首先我们观察一下上图用常规拉链法所造出的哈希表,它有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;}
0 0
- HashTable的拉链法的数组实现
- Java 实现的拉链法实现
- Scala数组的拉链操作
- Pyhton Map 拉链法 的实现
- 一个哈希表的简单实现拉链法
- 哈希桶的实现(拉链法)
- HASH表的java实现(拉链法)
- HashTable哈希表拉链法实现(C语言)
- 用拉链法实现哈希算法的运算
- HASH表的实现(拉链法) - C/C++
- 拉链表的使用以及实现
- 拉链法实现哈希表
- hash表的拉链法解决冲突
- 基于拉链法的散列表
- 拉链的通常算法
- 须民的拉链
- 哈希表的【构造方法】【冲突处理方法】及【哈希拉链法的简单代码实现】
- js实现的下拉链表的联动效果
- ios8之后调用系统定位
- mysql主从复制(Master-Slave)
- Lucas-Kanade algorithm
- 无向图的邻接表描述和遍历
- 高血压
- HashTable的拉链法的数组实现
- Shell if语句用法小结
- 求字符串中由连续的相同字符组成的最长子串(如果有两个及两个以上的最长子串,则输出第二个)
- Linux 应用程序超过10秒未调度
- Reverse Linked List
- 第一篇博客
- 第14周 【项目1 - 小玩文件】(4)
- 从DirectX SDK升级到Windows SDK
- mysql安装for linux(二进制)