-
2020-07-19 19:31:53
先来了解一下Hash的基本思路:
设要存储对象的个数为num, 那么我们就用len个内存单元来存储它们(len>=num); 以每个对象ki的关键字为自变量,用一个函数h(ki)来映射出ki的内存地址,也就是ki的下标,将ki对象的元素内容全部存入这个地址中就行了。这个就是Hash的基本思路。
Hash为什么这么想呢?换言之,为什么要用一个函数来映射出它们的地址单元呢?
This is a good question.明白了这个问题,Hash不再是问题。下面我就通俗易懂地向你来解答一下这个问题。
现在我要存储4个元素 13 7 14 11
显然,我们可以用数组来存。也就是:a[1] = 13; a[2] = 7; a[3] = 14; a[4] = 11;
当然,我们也可以用Hash来存。下面给出一个简单的Hash存储:
先来确定那个函数。我们就用h(ki) = ki%5;(这个函数不用纠结,我们现在的目的是了解为什么要有这么一个函数)。
对于第一个元素 h(13) = 13%5 = 3; 也就是说13的下标为3;即Hash[3] = 13;
对于第二个元素 h(7) = 7 % 5 = 2; 也就是说7的下标为2; 即Hash[2] = 7;
同理,Hash[4] = 14; Hash[1] = 11;
好了,存现在是存好了。但是,这并没有体现出Hash的妙处,也没有回答刚才的问题。下面就来揭开它神秘的面纱吧。
现在我要你查找11这个元素是否存在。你会怎么做呢?当然,对于数组来说,那是相当的简单,一个for循环就可以了。
也就是说我们要找4次。
下面我们来用Hash找一下。
首先,我们将要找的元素11代入刚才的函数中来映射出它所在的地址单元。也就是h(11) = 11%5 = 1 了。下面我们来比较一下Hash[1]?=11, 这个问题就很简单了。也就是说我们就找了1次。这个就是Hash的妙处了。至此,刚才的问题也就得到了解答。至此,你也就彻底的明白了Hash了。
更多相关内容 -
为什么使用哈希表
2022-03-29 16:49:57哈希表 1、作用: 用来快速判断一个元素是否出现在集合中,可以将查找元素的复杂度从O(n)降低到O(1). 2、哈希映射 (1)对于每一个给定的关键字key值,通过哈希函数映射 f(key) 之后,就可以得到一个在哈希表M中 ...哈希表
1、作用:
用来快速判断一个元素是否出现在集合中,可以将查找元素的复杂度从O(n)降低到O(1).
2、哈希映射
(1)对于每一个给定的关键字key值,通过哈希函数映射 f(key) 之后,就可以得到一个在哈希表M中 记录该关键字的地址。
(2)通常的操作:
key % (总长度) = 哈希表M中的位置
每个关键字key对应的位置是固定的(3)<font color="red"存储的数据结构
在python中,其实就是一个字典。
将每个元素都对应一个序号,构成key-value的形式,存在字典中。关键字key的值是元素,经过哈希表映射之后得到的位置是value的值。
当需要查找元素的时候,直接利用dict[key] = value 的形式就可以找到。3、解决哈希碰撞问题
常用的解决方案有散列法和拉链法。散列法又分为开放寻址法和再散列法
4、哈希表的优势
(1)在列表查找中,使用最广泛的二分查找算法,复杂度为O(log2n),但其始终只能用于有序列表。普通无序列表只能采用遍历查找,复杂度为O(n)。
(2)拥有较为理想的哈希函数实现的哈希表,对其任意元素可以直接通过计算获取位置,查找速度始终为常数级,即O(1)。5、js中哈希表的实现
js中只有Map,没有HashMap。HashMap只是map的一种底层实现方式。
// 创建一个Map对象 var map = new Map(); // 可以用数组当中的下标作为key,也可以用值作为key // 检查key是否存在 map.has(key); // 通过key取对应的value map.get(key); // 删除 m.delete('Adam'); // 添加 m.set('Adam', 67);
6、哈希表的空间消耗
使用哈希表的时候,需要用到栈,所以空间复杂度为O(n)
-
数组、链表和哈希表
2022-03-18 15:20:47数组、链表和哈希表数组、链表和哈希表关系数组与链表的区别链表总结链表开源库—utlist.h哈希表开源C库—uthash简介uthash能做什么uthash包括的额外内容uthash效率简单使用定义hash数据结构从hash表查找item向hash...数组、链表和哈希表
数组、链表和哈希表关系
数组与链表的区别
(1)存储空间上
链表存放的内存空间可以是连续的,也可以是不连续的,数组则是连续的一段内存空间。一般情况下存放相同多的数据时,数组占用较小的内存,而链表还需要存放其前驱和后继的空间。
(2)长度的可变性
链表的长度是按实际需要可以伸缩的,而数组的长度是在定义时要给定的,如果存放的数据个数超过了数组的初始大小,则会出现溢出现象。
(3)查找效率:
按序号查找时,数组可以随机访问,时间复杂度为O(1),而链表不支持随机访问,平均需要O(n);按值查找时,若数组无序,数组和链表时间复杂度均为O(n),但是当数组有序时,可以采用折半查找将时间复杂度降为O(logn);
(4)插入删除时:
数组平均需要移动n/2个元素,而链表只需修改指针即可;
(5)空间分配方面:
(静态)数组从栈中分配空间, 对于程序员(某些编程语言如java对于堆内存的管理也交由程序自动控制,但性能肯定有差异)方便快速,但是自由度小。链表从堆中分配空间, 自由度大但是申请管理比较麻烦。链表
那么有没有一种数据结构可以结合该两者的优点呢?那就是哈希表。
哈希表将需要查找的key值,通过hash函数的计算,换算为数组的位置值。这样在查找时就可以直接定位数据的位置。它结合了数组的快速查询的优点又能融合链表方便快捷的增加删除元素的优势
总结
数组------查找快,修改慢!
链表------查找慢,修改快!
哈希表:是数组和链表的结合体。
注意:- 在程序变量中,数组和链表都只需要在栈上存储一个起始位置,占用一个变量位置即可。
- hash将需要定位的值通过hash函数换算为数据的位置值,以空间换时间。
链表开源库—utlist.h
介绍
utlist.h中包含了一组用于C结构体的通用链表宏。使用起来非常简单,只需要将utlist.h拷贝到你的项目,并包含进你的源码即可,utlist.h宏提供了基本的链表操作:添加、删除、排序、遍历。
源码获取
utlist.h的源码可以在GitHub上直接获取(src/utlist.h):
https://github.com/troydhanson/uthash
链表类型
utlist.h支持下面三种类型的链表:
- 单向链表
- 双向链表
- 环形双向链表
使用效率
- 头部添加:对所有的链表类型都是常量;
- 尾部添加:单向链表O(n);双向链表是常量;
- 删除:单向链表O(n);双向链表是常量;
- 排序:对所有链表类型都是O(n log(n));
- 有序链表遍历:对所有链表类型都是O(n);
- 无序链表遍历:对所有链表类型都是O(n);
哈希表开源C库—uthash
简介
C语言的标准库中没有哈希表的函数可以使用,但是可以通过第三方头文件uthash.h这个包来实现哈希表的操作。uthash 是C的比较优秀的开源代码,它实现了常见的hash操作函数,例如查找、插入、删除等待。该套开源代码采用宏的方式实现hash函数的相关功能,支持C语言的任意数据结构最为key值,甚至可以采用多个值作为key,无论是自定义的struct还是基本数据类型,需要注意的是不同类型的key其操作接口方式略有不通。
使用uthash代码时只需要包含头文件"uthash.h"即可。由于该代码采用宏的方式实现,所有的实现代码都在uthash.h文件中,因此只需要在自己的代码中包含该头文件即可。可以通过下面两种方式获取源代码。
- 通过官方下载链接:
官方GitHub地址
https://github.com/troydhanson/uthash
- 另外uthash的英文使用文档介绍可从下面网址获得:
uthash英文使用文档
http://troydhanson.github.io/uthash/ http://troydhanson.github.io/uthash/userguide.html
uthash能做什么
通过uthash软件,支持对hash表的item进行如下操作:
添加/替换(add/replace)
查找(find)
删除(delete)
统计(count)
迭代器(iterate)
排序(sort)uthash包括的额外内容
uthash 附带了三个“附加功能”。这些提供列表、动态数组和字符串:
- utlist.h为 C 结构提供链表宏。
- utarray.h使用宏实现动态数组。
- utstring.h实现了一个基本的动态字符串。
uthash效率
uthash的插入、查找、删除的操作时间都是常量,当然这个常量的值受到key以及所选择的hash函数的影响。
uthash共提供了7种函数函数,一般情况下选择默认的即可。如果对效率要求特别高时,可以再根据自己的需求选择适合自己的hash函数。
简单使用
定义hash数据结构
在自己的数据结构中添加UT_hash_handle的支持:
#include "uthash.h" struct my_struct { int id; /* we'll use this field as the key */ char name[10]; UT_hash_handle hh; /* makes this structure hashable */ }; struct my_struct *g_users = NULL;
- id是键(key);
- name是值(value),即自己要保存的数据域,这里可以根据自己的需要让它变成结构体指针或者其他类型都可以;
- hh是内部使用的hash处理句柄,在使用过程中,只需要在结构体中定义一个UT_hash_handle类型的变量即可,不需要为该句柄变量赋值,但必须在该结构体中定义该变量;
- Uthash所实现的hash表中可以提供类似于双向链表的操作,可以通过结构体成员hh的hh.prev和hh.next获取当前节点的上一个节点或者下一个节点。
注意:在uthash中,当您的结构添加到hash表中时,并不会被移动或拷贝到其他位置。这意味着在程序运行过程中,无论是对hash表进行添加或删除操作,都可以保证您数据结构的安全性。
从hash表查找item
struct my_struct *find_user(int user_id) { struct my_struct *s = NULL; HASH_FIND_INT(g_users, &user_id, s); return s; }
向hash表添加item
void add_user(struct my_struct *s) { HASH_ADD_INT(g_users, id, s ); }
从hash删除item
void delete_user(struct my_struct *user) { HASH_DEL(g_users, user); }
在实际操作时,需要特别注意以下三点:
- 与任何hash表一样,每个item都必须有唯一的key,因此uthash也要求key具有唯一性;
- 插入时,先查找,当键不在当前的hash表中时再进行插入,以确保键的唯一性;
- 需调用插入接口函数时需要明确告诉接口函数,自己定义的键变量的名字是什么。
最后
更多请阅读英文使用文档:
uthash英文使用文档 -
哈希表性能测试,为什么要用哈希表
2021-08-22 23:47:33哈希表性能测试,为什么要用哈希表简介哈希表性能测试代码测试结果为什么要用哈希表提高查询速度减少CPU资源的损耗用什么做哈希的key值写在最后 简介 我就默认大家都清楚哈希表的原理、用途了。今天这篇文章侧重于...哈希表性能测试,为什么要用哈希表
简介
我就默认大家都清楚哈希表的原理、用途了。今天这篇文章侧重于讲解使用哈希表的必要性,并且用实验数据和自己的推理作为佐证。
哈希表性能测试
代码
最简单的一个哈希例子,记录了学生id和成绩的映射。没考虑异常处理,没考虑数据合理性。
#include <stdio.h> #include <stdlib.h> #include <time.h> #define HASH_TABLE_SIZE 520000000 typedef struct { int id; int score; } id_and_score; typedef struct { id_and_score *val; int count; } HASH_TABLE; int m = 0; //初始化散列表 int init_hash_table(HASH_TABLE *H) { int i; m = HASH_TABLE_SIZE; H->count = m; H->val = (id_and_score *)malloc(m * sizeof(id_and_score)); for (i = 0; i < m; i++) { H->val[i].id = i; H->val[i].score = i+2; } return 1; } //散列函数 int hash_func(int key) { return key % m; } //散列表查找关键字 int search_by_hash(HASH_TABLE H, int key) { int addr = hash_func(key); while (H.val[addr].id != key) { addr = (addr + 1) % m; } return H.val[addr].score; } //遍历查找 int search_by_ergodic(HASH_TABLE H, int key) { int i = 0; while (i < HASH_TABLE_SIZE) { if (H.val[i].id == key) return H.val[i].score; i++; } return -1; } int main() { int time1, time2; HASH_TABLE H; int i; time1 = clock(); init_hash_table(&H); time2 = clock(); printf("建立哈希表耗费的时间是:%fs\n", (double)(time2 - time1)/CLOCKS_PER_SEC); time1 = clock(); int score = search_by_hash(H, 500000025); time2 = clock(); printf("搜索到500000025号学生的分数是:%d\n", score); printf("哈希法搜索耗费的时间是:%fs\n", (double)(time2 - time1)/CLOCKS_PER_SEC); time1 = clock(); score = search_by_ergodic(H, 500000025); time2 = clock(); printf("搜索到500000025号学生的分数是:%d\n", score); printf("遍历法搜索耗费的时间是:%fs\n", (double)(time2 - time1)/CLOCKS_PER_SEC); }
测试结果
响应时间:
CPU占用:
为什么要用哈希表
提高查询速度
在上边已经看到了,在5亿数据量下,使用哈希进行搜索耗时级别为零(耗时很小以至于clock函数都识别不出来),而遍历搜索需要1.5s左右。用哈希进行查找可以明显提高查询速度。
但当时有人可能问了:建立哈希需要将近九秒,这样算下来,总时间应该变多了啊,为什么哈希表建立这么耗时,我们还是要使用它呢?
这样想其实也没有问题,但是我们不能忽略使用场景而空谈。什么时候用哈希呢?答案是查询量非常大的时候。在这种情况下,我们当然不能查一次数据就建一次哈希表;而是一开始,当进程或系统启动的时候,就把数据都加载到内存里边,建立哈希表。这样的话,我们只是在系统启动的时候耗费了9s中建立哈希表。而其他任何时候查询都几乎不耗时间。
在查询量很大的情况下,比如说一天查几百万次(例如某度),这样子用哈希查询相比遍历法节约了几百万秒。查询频率越高,哈希的优势越大。
减少CPU资源的损耗
其实更重要的一点就是节约CPU资源了。
CPU资源是非常宝贵的。如果我们用遍历法,遍历这五亿多条数据,CPU瞬间就拉满了。在上图中,我仅仅一个用户进行查询就耗费了30%的CPU。如果是比较大的应用,同一时间可能有成千上万个用户查询。这么搞CPU,就是再高端的服务器也扛不住啊。
用什么做哈希的key值
大家都知道哈希表是key-value的组合。那么我们应该如何选取key值呢?
最重要的一点:key值不能经常变化。大家在上边也看到了,建立哈希表需要的时间非常长。如果我们频繁改动key值,就要频繁的重建哈希,即浪费时间,也浪费资源。
所以我们一般将较为固定的值作为key,比如url,用户的id等。
写在最后
大家有什么疑问请尽管提,有指导意见也请指出来。我会尽力回答和改正。
-
哈希表总结
2021-11-28 16:20:00一,哈希表概念 1.概念 2.初次简单模拟 3.模拟总结 二,哈希冲突(哈希碰撞) 1.概念 2.分析 初步分析: 避免冲突时的哈希函数设计: 常见的哈希函数: 3.解决 1.闭散列 2.开散列 三,模拟实现哈希桶... -
哈希表原理
2019-07-08 18:05:07哈希表是最常用的数据结构之一,对于其用法,大家都非常熟悉,这里详细探讨一下其原理。哈希表的底层实际上是基于数组来存储的,当插入键值对时,并不是直接插入该数组中,而是通过对键进行Hash运算得到Hash值,然后... -
哈希表(Java实现)
2022-02-04 10:31:51哈希表(Java实现) -
哈希表的理论讲解
2022-05-23 16:21:38无序关联容器:unordered_set和unordered_map,底层用链式哈希表。 哈希表增删查效率非常高,趋近于O(1),但是没有办法达到绝对的O(1)。 哈希表在进行大量的查询会用到,只要是有速度比较快的查询的需求,都可以... -
哈希表:散列表
2022-03-16 16:22:20哈希表 -
什么是哈希表、哈希冲突?
2021-05-21 20:10:53哈希表的优势在于:相比于简单的数组以及链表,它能够根据元素本身在第一时间,也就是时间复杂度为0(1)内找到该元素的位置。这使得它在查询和删除、插入上会比数组和链表要快很多。因为他们的时间复杂度为o(n)。 ... -
【算法竞赛模板】哈希表(开放寻址法、拉链法、字符串哈希方式)
2022-04-13 12:01:06算法竞赛模板,详细讲解哈希表模板(开放寻址法、拉链法、字符串哈希值代码) -
简要介绍哈希表原理,JavaScript实现哈希表
2022-02-18 21:52:20哈希表通常是基于数组进行实现的,但是相对于数组,它有很多优势: 它可以提供非常快速的插入-删除-查找操作 无论多少数据,插入和删除需要接近常量的时间:即O(1)的时间级。实际上,只需要几个机器指令即可完成。 ... -
【算法与数据结构 10】哈希表——高效查找的利器
2020-09-24 17:03:213.2 哈希表的优缺点 优势:它可以提供非常快速的插入-删除-查找操作,无论多少数据,插入和删除值需要接近常量的时间。在查找方面,哈希表的速度比树还要快,基本可以瞬间查找到想要的元素。 不足:哈希表中的数据... -
数据结构中的哈希表
2021-12-02 09:22:17哈希表通常是基于数组进行实现的,但是相对于数组,哈希表有许多的优势: 它可以提供非常快速的插入-删除-查找操作。 在哈希表种,无论多少数据,插入和删除值只需要接近常量的时间:即O(1)的时间级。在进行操作时... -
哈希表(JavaScript实现)
2021-12-17 15:07:49哈希表是一种非常重要的数据结构,几乎所有的编程语言都有直接或者间接的应用这种数据结构,它通常是基于数组实现的,当时相对于数组,它有更多的优势: 它可以提供非常快速的插入-删除-查找操作。 哈希表的速度比... -
哈希表
2019-10-26 16:19:49写完前面的两篇博客,我感觉经历了两个极端: 第一篇:链表队列,往队列里面添加、删除、插入元素都很舒服,但是如果要查找一个元素,就要从头节点或者尾节点...所以,能不能把这两个的优势给结合起来呢? Hash表 ... -
哈希函数和哈希表
2021-09-06 21:35:28哈希表 主要作用:加快查找速度。可以近似看成O(1). 哈希函数特点: 1.其输入无限,输出有限。 2.每次相同的输入一定得到相同的输出。不同的输入也可能产生相同的输出。(哈希碰撞) 3.输出分布是绝对离散的,不会... -
IPFS系列 - 分布式哈希表(DHT)
2020-05-18 10:36:09DHT的全称是Distributed Hash Table,即分布式哈希表技术,是一种分布式的存储方法。这种分布式网络不需要中心节点服务器,而是每个客户端负责一个小范围的路由,并负责存储一小部分数据,从而实现整个DHT网络的寻址... -
红黑树与哈希表的比较(数据结构!)
2020-04-11 10:22:31而相对于哈希表这个数据结构来讲,哈希表的插入删除操作的理论上时间复杂度是常数时间的,这有个前提就是哈希表不发生数据碰撞。在发生碰撞的最坏的情况下,哈希表的插入和删除时间复杂度最坏能达到O(n)。而在一般... -
JavaScript实现哈希表
2020-07-03 15:54:59参考资料 JavaScript实现哈希表 -
数组 链表 哈希表 区别详解
2020-08-14 11:40:27三、哈希表 1、简介 散列法,是数组和链表的结合体 2、举例 即将输入的数据通过hash函数得到一个key值,输入的数据存储到数组中下标为key值的数组单元中去 3、优缺点 1.既能具备数组的快速查询的优点... -
JavaScript数据结构与算法 - 哈希表详解
2021-05-31 10:44:30哈希表通常是基于数组进行实现的,但是相对于数组,它也很多的优势和不足. 优势: 它可以提供非常快速的插入-删除-查找操作 无论多少数据,插入和删除值需要接近常量的时间:即O(1)的时间级.实际上,只需要几个机器指令... -
hash.rar_HASH算法_fpga hash_hash_zebra85v_哈希表Verilog
2022-07-14 02:40:28哈希算法的高速FPGA实现,本文hi介绍,有少量算法介绍,共16页 -
使用ES5,ES6实现哈希表(散列表)
2021-11-15 15:58:261.哈希表通常是基于数组实现的,但是相对于数组,他存在更多的优势 2.哈希表可以提供快速的插入-删除-查找操作 3.插入和删除的时间复杂度为O(n); 4.哈希表的速度比树还要快 5.哈希表结构是数组,原理在于下标值的一... -
数据结构 5分钟带你搞定哈希表(建议收藏)!!!
2021-05-23 15:26:51散列表(Hash table,也叫哈希表),是根据键(Key)而直接访问在内存存储位置的数据结构。也就是说,它通过计算一个关于键值的函数,将所需查询的数据映射到表中一个位置来访问记录,这加快了查找速度。这个映射... -
数据结构-哈希表(java实现)
2020-12-18 11:29:16文章目录1、哈希表介绍2、哈希函数H(k)哈希函数的构造方法:(1)直接定址法(2)数字分析法(3)平方取中法(4)折叠法(5)除留余数法(6)随机数法3、解决哈希碰撞1、开放地址法2、链地址法(拉链法)4、实例:... -
数据结构与算法(七)-哈希表(HashTable)
2022-01-11 17:04:47哈希表通常是基于数组实现的,但是相对于数组,它存在更多优势 1. 哈希表的优点 哈希表可以提供非常快速的插入-删除-查找操作; 无论多少数据,插入和删除值都只需要非常短的时间,即O(1)的时间级。实际上,只需要... -
哈希表学习
2022-03-07 17:44:55数组+链表的哈希表学习。 个人理解,简单来说是通过数组,将数组中的每一个位置都被指针指向链表中的某一个存在,需要注意的还是哈希表中可能存在