数据结构之哈希(hash)表

1.哈希表的定义

  这里先说一下哈希(hash)表的定义:哈希表是一种根据关键码去寻找值的数据映射结构,该结构通过把关键码映射的位置去寻找存放值的地方,说起来可能感觉有点复杂,我想我举个例子你就会明白了,最典型的的例子就是字典,大家估计小学的时候也用过不少新华字典吧,如果我想要获取“按”字详细信息,我肯定会去根据拼音an去查找 拼音索引(当然也可以是偏旁索引),我们首先去查an在字典的位置,查了一下得到“安”,结果如下。这过程就是键码映射,在公式里面,就是通过key去查找f(key)。其中,按就是关键字(key),f()就是字典索引,也就是哈希函数,查到的页码4就是哈希值。

通过字典查询数据

2.哈希冲突

  但是问题又来了,我们要查的是“按”,而不是“安,但是他们的拼音都是一样的。也就是通过关键字按和关键字安可以映射到一样的字典页码4的位置,这就是哈希冲突(也叫哈希碰撞),在公式上表达就是key1≠key2,但f(key1)=f(key2)。冲突会给查找带来麻烦,你想想,你本来查找的是“按”,但是却找到“安”字,你又得向后翻一两页,在计算机里面也是一样道理的。

  但哈希冲突是无可避免的,为什么这么说呢,因为你如果要完全避开这种情况,你只能每个字典去新开一个页,然后每个字在索引里面都有对应的页码,这就可以避免冲突。但是会导致空间增大(每个字都有一页)。

  既然无法避免,就只能尽量减少冲突带来的损失,而一个好的哈希函数需要有以下特点:

  1.尽量使关键字对应的记录均匀分配在哈希表里面(比如说某厂商卖30栋房子,均匀划分ABC3个区域,如果你划分A区域1个房子,B区域1个房子,C区域28个房子,有人来查找C区域的某个房子最坏的情况就是要找28次)。

  2.关键字极小的变化可以引起哈希值极大的变化。

  比较好的哈希函数是time33算法。PHP的数组就是把这个作为哈希函数。

  核心的算法就是如下:

unsigned long hash(const char* key){unsigned long hash=0;for(int i=0;i<strlen(key);i++){hash = hash*33+str[i];}  return hash;
}

3.哈希冲突解决办法

   如果遇到冲突,哈希表一般是怎么解决的呢?具体方法有很多,百度也会有一堆,最常用的就是开发定址法和链地址法。

  1.开发定址法

  如果遇到冲突的时候怎么办呢?就找hash表剩下空余的空间,找到空余的空间然后插入。就像你去商店买东西,发现东西卖光了,怎么办呢?找下一家有东西卖的商家买呗。

  由于我没有深入试验过,所以贴上在书上的解释:

  2.链地址法

  上面所说的开发定址法的原理是遇到冲突的时候查找顺着原来哈希地址查找下一个空闲地址然后插入,但是也有一个问题就是如果空间不足,那他无法处理冲突也无法插入数据,因此需要装填因子(插入数据/空间)<=1。

  那有没有一种方法可以解决这种问题呢?链地址法可以,链地址法的原理时如果遇到冲突,他就会在原地址新建一个空间,然后以链表结点的形式插入到该空间。我感觉业界上用的最多的就是链地址法。下面从百度上截取来一张图片,可以很清晰明了反应下面的结构。比如说我有一堆数据{1,12,26,337,353...},而我的哈希算法是H(key)=key mod 16,第一个数据1的哈希值f(1)=1,插入到1结点的后面,第二个数据12的哈希值f(12)=12,插入到12结点,第三个数据26的哈希值f(26)=10,插入到10结点后面,第4个数据337,计算得到哈希值是1,遇到冲突,但是依然只需要找到该1结点的最后链结点插入即可,同理353。

  

哈希表的拉链法实现

  下面解析一下如何用C++实现链地址法。

  第一步。

  肯定是构建哈希表。

  首先定义链结点,以结构体Node展示,其中Node有三个属性,一个是key值,一个value值,还有一个是作为链表的指针。还有作为类的哈希表。

#define HASHSIZE 10
typedef unsigned int uint;
typedef struct Node{const char* key;const char* value;Node *next;
}Node;class HashTable{
private:Node* node[HASHSIZE];
public:HashTable();uint hash(const char* key);Node* lookup(const char* key);bool install(const char* key,const char* value);const char* get(const char* key);void display();
};

  然后定义哈希表的构造方法

HashTable::HashTable(){for (int i = 0; i < HASHSIZE; ++i){node[i] = NULL;}
}

  第二步。

  定义哈希表的Hash算法,在这里我使用time33算法。

uint HashTable::hash(const char* key){uint hash=0;for (; *key; ++key){hash=hash*33+*key;}return hash%HASHSIZE;
}

  第三步。

  定义一个查找根据key查找结点的方法,首先是用Hash函数计算头地址,然后根据头地址向下一个个去查找结点,如果结点的key和查找的key值相同,则匹配成功。

Node* HashTable::lookup(const char* key){Node *np;uint index;index = hash(key);for(np=node[index];np;np=np->next){if(!strcmp(key,np->key))return np;}return NULL;
}

  第四步。

  定义一个插入结点的方法,首先是查看该key值的结点是否存在,如果存在则更改value值就好,如果不存在,则插入新结点。

bool HashTable::install(const char* key,const char* value){uint index;Node *np;if(!(np=lookup(key))){index = hash(key);np = (Node*)malloc(sizeof(Node));if(!np) return false;np->key=key;np->next = node[index];node[index] = np;}np->value=value;return true;
}

  

4.关于哈希表的性能

  由于哈希表高效的特性,查找或者插入的情况在大多数情况下可以达到O(1),时间主要花在计算hash上,当然也有最坏的情况就是hash值全都映射到同一个地址上,这样哈希表就会退化成链表,查找的时间复杂度变成O(n),但是这种情况比较少,只要不要把hash计算的公式外漏出去并且有人故意攻击(用兴趣的人可以搜一下基于哈希冲突的拒绝服务攻击),一般也不会出现这种情况。

哈希冲突攻击导致退化成链表

出处:http://www.cnblogs.com/s-b-b/

转载于:https://www.cnblogs.com/LuckCoder/p/10465358.html

数据结构哈希表 转载相关推荐

  1. java hashtable 数据结构_数据结构--哈希表(Java)

    数据结构--哈希表(Java) 介绍 哈希表 底层是 数组加链表 或者是 数组加二叉树 ,一个数组里面有多个链表,通过散列函数来提高效率 代码 package cn.guizimo.hashtab; ...

  2. Python中常用的数据结构---哈希表(字典)

    Python中常用的数据结构-哈希表(字典) 常用的数据结构有数组.链表(一对一).栈和队列.哈希表.树(一对多).图(多对多)等结构. 在本目录下我们将讲解,通过python语言实现常用的数据结构. ...

  3. 数据结构——哈希表的详解与实现

    数据结构--哈希表(HashTable) 1.前言 ​ 当我们频繁的查找数据中的某个元素时,我们通常会选择数组来存放数据,因为数组的的内存是连续的,可以直接通过下标访问数据,但是它添加和删除数据比较麻 ...

  4. 数据结构哈希表的实现与设计

    数据结构哈希表查找姓名的课程设计 有没有大神能帮忙写一下这道题,课设的题目.用C++语言 问题描述:针对某公司中花名设计哈希表,并完成相应的建表和查表程序,基本要求: (1)假设花名为汉字拼音形式.名 ...

  5. 算法笔记(三)特殊数据结构——哈希表、有序表、并查集、KMP、Manacher、单调栈、位图、大数据类题

    layout: post title: 算法笔记(三)特殊数据结构--哈希表.有序表.并查集.KMP.Manacher.单调栈.位图.大数据类题 description: 算法笔记(三)特殊数据结构- ...

  6. openssl lhash 数据结构哈希表

    哈希表是一种数据结构,通过在记录的存储位置和它的关键字之间建立确定的对应关系,来快速查询表中的数据: openssl lhash.h 为我们提供了哈希表OPENSSL_LHASH 的相关接口,我们可以 ...

  7. 数据结构 — 哈希表

    目录 文章目录 目录 哈希表 哈希表 哈希表,又称为散列表,是根据键值对(Key/Value)进行访问的数据结构,它让 Value 经过哈希函数的转换映射到哈希表对应的位置上,查找效率非常高.哈希索引 ...

  8. 哈希表数据结构_Java数据结构哈希表如何避免冲突

    前言 一.哈希表是what? 这是百度上给出的回答: 简而言之,为什么要有这种数据结构呢? 因为我们想不经过任何比较,一次从表中得到想要搜索的元素.所以就构造出来了哈希表,通过某种函数(哈希函数)使元 ...

  9. 数据结构-----------------------哈希表(最通俗易懂的文章)

    哈希表 简要 通俗来讲,哈希表是通过函数 (映射关系) 来直接寻找表中存储的关键字,哈希表也是一种数据结构,它是表结构的一种升级拓展,哈希就是一种函数映射,表是一种数据结构,那么合起来就叫哈希表 那么 ...

  10. 浅谈算法和数据结构: 哈希表

    作者: yangecnu(yangecnu's Blog on 博客园) 出处:http://www.cnblogs.com/yangecnu/  http://www.cnblogs.com/yan ...

最新文章

  1. cors在服务器还是接口_cors
  2. 【转摘】Word提升效率的快捷键
  3. c 文件夹打包解包_linux中文档的压缩与打包
  4. java disjoint_java – Union Find算法的应用(Disjoint Set)
  5. 取pi的前8位的解压密码_两种方式实现取16位变量的高低8位, 不严谨对比
  6. Codeforces Round #461 (Div. 2)B-Magic Forest+位运算或优雅的暴力
  7. windows下一键修改IP地址
  8. JAVA拓展新的数据库,SqlFaker:轻量级、易拓展的Java数据库智能填充开源库
  9. database rough 1
  10. AR技术在物流运输中的应用
  11. 手撕:经典问题的遗传算法代码
  12. C++ Primer 笔记——IO类
  13. R语言 K-M生存分析,ggplot2制作好看的生存曲线
  14. 游虎DOTA专区 - 内容丰富的DOTA专区,DOTA录像分析很不错的..
  15. 如何使用 Docker 部署一个私有化的为知笔记
  16. 系统调用是什么,你用过哪些系统调用
  17. 液晶屏偏光片的选用规则?
  18. js正则匹配以{开头,以}结尾怎么写?
  19. h5游戏间接转换为微信小游戏
  20. Myeclipse链接sql server 2005是出现Error while performing database login with the sql2005 driver:

热门文章

  1. 解决 Error:No suitable device found: no device found for connection System eth0
  2. Handler处理机制
  3. greenplum管理员日常任务
  4. atomic_fetch_add
  5. Linux进程的管理与调度(四) -- Linux下的进程类别以及其创建方式
  6. Linux死锁检测-Lockdep
  7. ffmpeg对H.264进行rtp打包
  8. oracle语句_ORACLE 常用语句实例:CTE MERGE 结合
  9. shell 逐行读取文件
  10. Ubuntu20.04环境下 安装Tensorflow