数据结构与算法Day16----散列表(下)
一、LRU(Least recently used,最近最少使用)缓存淘汰算法:
1、仅使用链表:
【数据结构与算法Day16----散列表(下)】??维护一个按照访问时间从大到小有序排列的链表结构。因为缓存大小有限,当缓存空间不够,需要淘汰一个数据的时候,我们就直接将链表头部的结点删除。当要缓存某个数据的时候,先在链表中查找这个数据。如果没有找到,则直接将数据放到链表的尾部;如果找到了,我们就把它移动到链表的尾部。因为查找数据需要遍历链表,所以单纯用链表实现的LRU缓存淘汰算法的时间复杂很高,是O(n)。
2、散列表和链表两种数据结构组合使用:
<1>、可以将这三个操作的时间复杂度都降低到O(1)。
<2>、具体结构:
文章图片
18599817-6725ca82e5c81bc9.png ??使用双向链表存储数据,链表中的每个结点处理存储数据(data)、前驱指针(prev)、后继指针(next)之外,还新增了一个特殊的字段hnext。因为我们的散列表是通过链表法解决散列冲突的,所以每个结点会在两条链中。一个链是刚刚我们提到的双向链表,另一个链是散列表中的拉链。前驱和后继指针是为了将结点串在双向链表中, hnext指针是为了将结点串在散列表的拉链中。
二、Redis有序集合:
1、集合的构成:
??在有序集合中,每个成员对象有两个重要的属性, key(键值)和score(分值)。
2、相关操作:
??①、添加一个成员对象;
??②、按照键值来删除一个成员对象;
??③、按照键值来查找一个成员对象;
??④、按照分值区间查找数据;
??⑤、按照分值从小到大排序成员变量;
三、HaLinkedHashMap:
1、实现方式:
??LinkedHashMap是通过散列表和链表组合在一起实现的。不仅支持按照插入顺序遍历数据,还支持按照访问顺序来遍历数据。
2、这段代码打印顺序分析:
// 10是初始大小, 0.75是装载因子, true是表示按照访问时间排序
HashMap m = new LinkedHashMap<>(10, 0.75f, true);
m.put(3, 11);
m.put(1, 12);
m.put(5, 23);
m.put(2, 22);
m.put(3, 26);
m.get(5);
for (Map.Entry e : m.entrySet()) {
System.out.println(e.getKey());
}
每次调用put()函数,往LinkedHashMap中添加数据的时候,都会将数据添加到链表的尾部,所以,在前四个操作完成之后,链表中的数据是下面这样:
文章图片
在第8行代码中,再次将键值为3的数据放入到LinkedHashMap的时候,会先查找这个键值是否已经有了,然后,再将已经存在的(3,11)删除,并且将新的(3,26)放到链表的尾部。所以,这个时候链表中的数据就是下面这样:
文章图片
当第9行代码访问到key为5的数据的时候,我们将被访问到的数据移动到链表的尾部。所以,第9行代码之后,链表中的数据是下面这样:
文章图片
最后打印出来的数据是1, 2, 3, 5。
由此可见,HaLinkedHashMap一个支持LRU缓存淘汰策略的缓存系统。LinkedHashMap中的“Linked”实际上是指的是双向链表,并非指用链表法解决散列冲突。
推荐阅读
- JAVA(抽象类与接口的区别&重载与重写&内存泄漏)
- Docker应用:容器间通信与Mariadb数据库主从复制
- 《真与假的困惑》???|《真与假的困惑》??? ——致良知是一种伟大的力量
- 第326天
- Shell-Bash变量与运算符
- 画解算法(1.|画解算法:1. 两数之和)
- 逻辑回归的理解与python示例
- Guava|Guava RateLimiter与限流算法
- 我和你之前距离
- CGI,FastCGI,PHP-CGI与PHP-FPM