键值对的高效插入与查询-hash-哈希
来源:互联网 发布:电子商务软件教材 编辑:程序博客网 时间:2024/05/16 16:17
今天看了有关hash方面的源码,以及上网搜索了一些百家之谈,我也说一下心得体会。
由于开发是C语言,所以想c++的vector,map等用不到,说白了就是要用C语言构建类似vector的东西。
在我看来,今天说的哈希结构非常像vector,下面来说一下:
我读的代码是 redis 源码里面的dict.c dict.h
这个dict专门用于存储键值对的东西,并不局限于字符串,还可以是别的类型。下面说一下dict实现的要点部分。
1. dict 是可伸缩的,初始化的时候,dict只有 4个桶(redis初始化为4),每个桶里面有一条锁链,链子上的每个 结 就是 键值对。
2.数据如何插入、修改? 首先一个键值对要插入,先用一个hash算法,算出键的hash,然后拿这个hash跟 当前桶的个数-1(也就是4-1)相与,结果就是它要进入的桶的编号,编号找到了,然后遍历一遍这个桶里面的锁链,如果键已经存在,则把值进行替换,这就是修改操作。如果没有找到,则将新的键值对插入到锁链的头部。
2.删除操作呢? 与插入雷同,先hash,再确定桶编号,再遍历锁链,找到后 断链删除。
3.查询? 不说了,你肯定会了。
OK,到这里为止,已经全部讲完了,但是有个问题,加入插入了上百万键值对,就4个桶,会导致什么?? 桶里面的链子太长了每个链子长度都在几十万,导致增删改查都极其缓慢。
所以要引入一个机制,如何避免这个问题。下面还是拿redis的解决方案。
1.设定一个比例,叫radio,比如等于5(redis默认值)
2.假如目前有4个桶,举个栗子 , 但是插入了 23个键值对,理论上来说,这23个键值对会均匀分布到4个桶中,毕竟hash算法产生的值可以看成随机值,与(4-1)做与操作,得出的值0,1,2,3,的概率差不多。 这个radio这时就起作用了, 用 23/4 = 5.X ,这个值大于了 5 ,所以触发扩容操作也就是 所谓的 expand操作,扩容很凶残, 直接就是 当前桶数*2 ,所以这时桶变成了8个。
3.新桶有了,该把旧桶的数据转移到新桶中,怎么转移呢? 遍历旧桶中的每个锁链,取出每个键值对,然后重新算hash,算完就用新的hash 与 (8-1)相与,这时得到新的桶编号,找到了自己的新桶,然后扣在新桶的锁链上。这个过程就叫 rehash。
相信上面的举例解释够白话了,不可能听不懂。归纳一下,hash做的dict结构 采用 数组与链表两种常见结构,数组就是一个个的桶,链表就是桶中的锁链。通过与操作可以快速算出桶编号,通过 bucket【i】可以瞬间定位桶地址,找到了桶,然后通过一个radio阈值,确保锁链不会太长,所以会很快的完成查询功能。
上面讲的是原理,其实真是情况跟上面不一样,rehash操作是个费时操作,所以如果要插入一个键值对,引发扩容,进而引发rehash,会导致本次插入耗时过长,所以需要采取一些措施。
1. 两个桶数组,一个桶做缓冲用。
2.rehash操作分批进行,比如一次移一个桶或者几个桶,这些还是自己去看源码吧。
- 键值对的高效插入与查询-hash-哈希
- HASH 大量插入与查询
- python 查询mysql的时候以键值对方式查询
- php 妙用数组键值对实现固定数据的查询
- Python 查询的数据库中的数据 关键值转换成键值对形式
- C++实现哈希表的创建,销毁,键值插入与删除
- std::map 如何插入键值对
- 高效查询当前插入后记录的自增长ID
- 关于索引与查询的hash
- 泛型与键值对
- HashTable键值对集合 及它与Dictionary的区别
- 从注册表中查询某一键值对
- Redis 数据库之哈希键值对(hash)
- [perl] 支持对key正则匹配查询值的hash
- 高效的字符串Hash公式
- 对加密数据的高效相似性查询(二)
- 高效的插入排序
- 重复键值对的解决方案
- 详解TensorBoard如何调参
- Tensorflow快速入门1--实现K-Means聚类算法
- hdu5920-Ugly Problem(强行模拟)
- 很全的SQL语句,值得收藏
- Batch Normalization 学习笔记
- 键值对的高效插入与查询-hash-哈希
- [深度学习PART I] 单层感知器
- encode string with shortest length(路还很远)
- 逻辑回归--sklearn基本使用
- 作为程序员,我们应不应学好英语?
- Linux 新增开机启动服务
- Django中的数据库模型类-models.py(一对一的关系)
- keras实现VGG16 CIFAR10数据集
- 在map上标记point