网站首页 > java教程 正文
原理如下图
为了编码方便处理各种边界值,冗余一个head和tail 来确保不会出现空指针,简化编码。
源代码如下:
package com.cache;
import java.util.HashMap;
import java.util.Map;
/**
* 双向链表+HashMap实现LRU
* 1.双向链表的好处是写代码方便,知道前后,删除起来更快。若是用单向也行,但是代码写起来麻烦。
* 2.HashMap的作用是提高操作(含插入、查询、删除)效率,存储key放在链表的哪个节点。操作时
* 能直接找到对应的节点操作。如果没有HashMap,每次操作都要去遍历链表找到要操作的节点才能操作。
* 3.为了操作方便,设立头尾两个固定的节点,无业务语义
*
* @author chris
*/
public class LruCacheByDoublyLinkedListAndHashMap<K, V> {
//定义节点
class Node {
//Node值,此处存储的是缓存的value值,key值在此处也冗余一个
K key;
V value;
//定义节点的前后节点位置
Node pre;
Node next;
public Node() {
}
public Node(K key, V value) {
this.key = key;
this.value = value;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(String.format("%s:%s ", key, value));
return sb.toString();
}
}
//定义双向链表
class DoublyLinkedList {
//头部节点
Node head;
//尾部节点
Node tail;
//链表初始化时,头尾都是一个,串联起来
public DoublyLinkedList() {
head = new Node();
tail = new Node();
head.next = tail;
tail.pre = head;
}
//当一个节点被访问时,把他放到队头
public synchronized void addToFirst(Node node) {
//~~把当前节点插入非head最前面
//当前节点指向原第一个节点
node.next = head.next;
//原第一个节点,指向当前节点
head.next.pre = node;
//~~调整head到第一位
//当前节点的上一个节点改成head
node.pre = head;
//head的下一阶段改成当前节点
head.next = node;
}
//当一个节点被访问时,把他放到队头
public synchronized void moveToFirst(Node node) {
//当前前节点的上下两个节点先调整好
Node preNode = node.pre;
Node nextNode = node.next;
preNode.next = nextNode;
nextNode.pre = preNode;
//~~把当前节点插入非head最前面
//当前节点指向原第一个节点
node.next = head.next;
//原第一个节点,指向当前节点
head.next.pre = node;
//~~调整head到第一位
//当前节点的上一个节点改成head
node.pre = head;
//head的下一阶段改成当前节点
head.next = node;
}
public synchronized K remove(Node node) {
//把下一元素,指向前一元素
node.next.pre = node.pre;
//把前一元素的下一元素,指向下一元素
node.pre.next = node.next;
//废弃掉当前元素
node.next = null;
node.pre = null;
return node.key;
}
public synchronized K removeLast() {
//如果当前没有节点,则不删除
if (head.next == tail) {
return null;
}
//找出要被删除的节点
Node toRemove = tail.pre;
//执行删除
return remove(toRemove);
}
}
//~~ LRU 开始实现
//定义双向链表
DoublyLinkedList cache;
//定义HashMap,key是目标key,value是Node
Map<K, Node> map;
//缓存容量
int capacity;
public LruCacheByDoublyLinkedListAndHashMap(int capacity) {
this.capacity = capacity;
cache = new DoublyLinkedList();
map = new HashMap<>();
}
//获取key
public V get(K key) {
//key不存在,直接返回空
if (!map.containsKey(key)) {
return null;
}
//key存在,获取key对于的值,并调整key对应的节点到队头
else {
Node node = map.get(key);
cache.moveToFirst(node);
return node.value;
}
}
//放入KV
public void put(K key, V value) {
//包含key,则覆盖,并挪到表头
if (map.containsKey(key)) {
Node node = map.get(key);
node.value = value;
cache.moveToFirst(node);
}
//不包含key,则要插入一个key,并判断空间是否已满,需要移除队列尾部的key
else {
if (map.size() >= capacity) {
K beRemoveKey = cache.removeLast();
map.remove(beRemoveKey);
}
Node newNode = new Node(key, value);
cache.addToFirst(newNode);
map.put(key, newNode);
}
}
@Override
public String toString() {
Node node = cache.head.next;
int count = 1;
StringBuilder sb = new StringBuilder();
while (node != null && node != cache.tail && count <= capacity) {
sb.append(String.format("%s:%s ", node.key, node.value));
count++;
node = node.next;
}
return sb.toString();
}
}
- 上一篇: 两个有序链表的合并
- 下一篇: 算法学习之合并两个有序链表
猜你喜欢
- 2024-12-31 删除链表中重复的节点
- 2024-12-31 LeetCode每日一题,合并K个升序链表
- 2024-12-31 算法学习之合并两个有序链表
- 2024-12-31 两个有序链表的合并
- 2024-12-31 【约瑟夫环】C语言数组法+java循环链表法
- 2024-12-31 Java手写单向链表
- 2024-12-31 java判断链表是否有环(两种方式实现)
- 2024-12-31 JAVA 反转链表
- 2024-12-31 算法篇:图解双向链表及Java实现
- 2024-12-31 剑指Offer (十五):反转链表(Java版)
你 发表评论:
欢迎- 04-24Java Collections 工具类集合框架中常用算法解析
- 04-24桶排序的简单理解
- 04-24Java集合框架底层实现原理大揭秘
- 04-24Java 集合框架全面解析:选对数据结构,提升开发效率
- 04-24c#集合排序
- 04-24Java面试中常被问到的集合类深度解读
- 04-24VBA技术资料MF278:对集合进行排序
- 04-24Spring 最常用的 7 大类注解,史上最强整理
- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)