手把手教你设计hash表与LRU缓存库

栏目: 数据库 · 发布时间: 5年前

内容简介:之前分享了《如果你用过也许你听过,那些底层都是使用树实现的。今天我先教你们用哈希实现。

一、背景

之前分享了《 链表 》系列、《 队列和栈 》系列、《 数组和字符串 》系列,今天我们来看看哈希技术,以及相关设计与实践应用。

如果你用过 set 或者 map 的话,应该知道这些数据结构可以做到快速插入、查找、删除等操作,而不像数组那样有 O(n) 的复杂度。

也许你听过,那些底层都是使用树实现的。今天我先教你们用哈希实现。

看完这篇文章,你会发现哈希这么简单。

另外业界的很多项目都使用到了哈希表来实现缓存,所以你看之后也能明白传说中的缓存是如何实现的。

二、原理

哈希表的关键思想就是使用哈希函数,将查询键映射到哈希桶上。

通过这样的操作,我们可以近乎于 O(1) 的复杂度完成各种操作。

具体来说。

插入时,根据哈希函数,确定数据键分配到哪个桶,然后将键值储存在这个桶。

查询时,使用相同的哈希函数,找到对应的桶,然后在桶里查找对应的键是否存在。

手把手教你设计hash表与LRU缓存库

如下图,0 映射到桶 0, 1987 和 2 映射到桶 2, 24 映射到桶 4.

这里可以看到一个问题:不同的键可能映射到相同的桶里。

此时最简单的做法是,同一个桶里的数据使用链表储存起来。

当然,查找的代价是同一个桶里需要遍历链表。

三、基本实现

实现哈希表的时候,需要注意几点。

1.桶大小一般固定(高级的会动态扩容)。

2.键的哈希函数固定。

3.查询操作最好封装起来,读写复用。

实现大概如下。

手把手教你设计hash表与LRU缓存库

四、缓存

上面的哈希表已经可以当做缓存来用了,数据太多的时候性能太低,所以需要增加一直淘汰策略。

这里我们增加一个 LRU 淘汰策略。

要实现 LRU 淘汰,需要先明白 LRU 淘汰的意思。

LRU 的全称是 Least Recently Used,即最近未使用。

所以,LRU淘汰策略就是优先淘汰最久没有使用的数据。

那怎么找到最久没使用的节点呢?

一种方法是储存所有数据的访问时间,然后根据最小的时间找数据。

这个可以使用平衡树来实现,但是树的成本有点高,负责度也是 O(log(n)) 的。

另一种方法就是双向链表。

如果我们将所有数据使用双向链表存起来,访问的数据移动到链表最前面,那需要淘汰的自然就是链表最后面的数据了。

由于是双向链表,我们可以直接定位到最后一个节点。

这样总体复杂度始终是 O(1)

所以实现 LRU 也很简单,只需要用之前教你们的 双向链表即可。

这里为了简单,我使用 STL 实现了一个简单版的 LRU缓存库。

如果你感兴趣,可以预先分配数据内存,然后通过下标来访问内存数据。 相信你实现了 LRU 缓存后,自己无论是对哈希表还是 LRU ,都会有不一样的理解。

手把手教你设计hash表与LRU缓存库 手把手教你设计hash表与LRU缓存库

四、最后

这里简单的介绍了 哈希表 和 LRU 缓存库。

实际的算法比赛中,我们不需要自己实现哈希表,一般直接使用 set 或者 map

set 用来判断一个元素是否存在一个集合里面, map 用来储存映射关系。

有了 setmap 在手,很多问题都迎刃而解。

-EOF-


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

PHP程序设计

PHP程序设计

Kevin Tatroe、Rasmus Lerdorf / 邓云佳 / 中国电力出版社 / 2003-7-1 / 68.00

本书涵盖了创建一个高效PHP Web应用程序所需要的所有技术,其内容包括:PHP语言基础的详细信息,包括数据类型、变量、操作符和流控制语句。用专门章节讨论关于函数、字符串、数组和对象的基本内容。涵盖通用的PHP Web应用程序设计技术,如表单处理和验证、会话跟踪以及cookie。用和数据库无关的PEAR DB库与关系数据库(如MySQL和Oracle)进行交互的内容。介绍用PHP生成动态图像、创建一起来看看 《PHP程序设计》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码