LRU算法java实现
Posted 大树的困惑
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LRU算法java实现相关的知识,希望对你有一定的参考价值。
LRU算法java实现
LRU算法是一种缓存淘汰策略
比如我们的电脑或者手机,在内存有限的情况下,它仅会将最近使用过的文档,文件,程序缓存在内存中…
以及我们手机中后台应用的排序,也是更具最新使用情况进行排序的
Leetcode中有关于LRU的题目,基于这道题进行探讨
设计和构建一个“最近最少使用”缓存,该缓存会删除最近最少使用的项目。缓存应该从键映射到值(允许你插入和检索特定键对应的值),并在初始化时指定最大容量。当缓存被填满时,它应该删除最近最少使用的项目。
它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果密钥 (key) 存在于缓存中,则获取密钥的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果密钥不存在,则写入其数据值。当缓存容量达到上限时,它应该在写入新数据之前删除最近最少使用的数据值,从而为新的数据值留出空间。
LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得密钥 2 作废
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得密钥 1 作废
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4
考虑使用什么数据结构:
get,put 既要查询,又要写入
哈希表查找快
链表有顺序之分,插⼊删除快,但是查找慢。
所以将两者有效的结合成哈希链表
单向链表:单向链表的java简单实现
双向链表:双向链表的java简单实现
我们需要分析什么情况下会影响排序
1.当你新增节点时,该节点则是优先级最高的
2.当你获取/查询某个节点时,该节点优先级也要变成最高的
什么情况下会影响整体的数据量
1.当你新增节点时
2.当你删除节点时
3.当你容量满的时候,你新增节点的时候,需要删除优先级最低的哪个节点
这里使用双向链表中的head,tail 头节点/和尾节点这样的逻辑结构引用作为优先级的代表
当节点处于tail时,优先级最低
当节点处于head时,优先级最高
下面看下代码的实现
package DataStrct.LRU;
import java.util.HashMap;
/**
* @author luke
* @date 2021/4/1821:09
*/
public class LRUDemo
public static void main(String[] args)
// DoubleLinklist doubleLinklist = new DoubleLinklist(new Node(1, 1));
// doubleLinklist.addfirst(new Node(2, 2));
// doubleLinklist.addfirst(new Node(3, 3));
// doubleLinklist.addfirst(new Node(4, 4));
// doubleLinklist.addfirst(new Node(5, 5));
// doubleLinklist.print_list();
// System.out.println(doubleLinklist.size());
// System.out.println("---------------");
// doubleLinklist.del_last();
// doubleLinklist.print_list();
// System.out.println("-----------del");
// doubleLinklist.del(new Node(4,2));
// doubleLinklist.print_list();
LRU cache = new LRU(1);
cache.put(2, 1);
System.out.println(cache.get(2));
// cache.put(2, 2);
// System.out.println(cache.get(1)); // 返回 1
// cache.put(3, 3); // 该操作会使得密钥 2 作废
// System.out.println(cache.get(2)); // 返回 -1 (未找到)
// cache.put(4, 4); // 该操作会使得密钥 1 作废
// System.out.println(cache.get(1)); // 返回 -1 (未找到)
// System.out.println(cache.get(3)); // 返回 3
// System.out.println(cache.get(4)); // 返回 4
static class LRU
//hash表
HashMap<Integer,Node> map;//hash表
DoubleLinklist dbl;//存储节点的双向链表
int cap;//缓存的容量
//初始化
public LRU(int cap)
this.cap = cap;
map = new HashMap<>();
dbl= new DoubleLinklist();
/**
* 1.get () 获取某个节点 -->对应的该节点会被提到优先级最高
* 2.put () 添加某个节点 -->添加的节点优先级最高
*/
public int get(int key)
if (!map.containsKey(key))//map用于维护已添加有效的节点,查询快
return -1;
//获取节点值
int value = map.get(key).value;
//对应的节点提到最高级别
put(key,value);
return value;
public void put (int key ,int value )
//根据传入key value 构建新的节点
Node node = new Node(key, value);
//添加新节点先判断是否存在改节点
if(map.containsKey(key))
//如果以存在,删除旧节点,将新节点添加到头部
map.remove(key);
map.put(key,node );
dbl.del(node);
dbl.addfirst(node);
else if(!map.containsKey(key))
//如果不存在该节点的话说明是新增节点,新增节点要判断容量的问题
int size = dbl.size();
if (size==cap)
//如果当前的链表长度和容量上限相等时,需要剔除链表中最后一位
Node lastnode = dbl.del_last();
if(lastnode!=null)
map.remove(lastnode.key);
//并将新节点添加到链表的头部
dbl.addfirst(node);
map.put(key,node );
else
dbl.addfirst(node);
map.put(key,node );
/**
* 节点类
*/
static class Node
int key;
int value;
Node next, pre;
public Node(int key, int value)
this.key = key;
this.value = value;
@Override
public String toString()
return "Node" +
"key=" + key +
", value=" + value +
'';
static class DoubleLinklist
Node head;
Node tail;
public DoubleLinklist()
/**
* 初始化链表
*
* @param node
*/
public DoubleLinklist(Node node)
this.head = node;
this.tail = node;
/**
* 1.头插
* 2.尾插
* 3.删除最后一个节点 用于删除当添加的节点达到容量上限时删除优先级最低的
* 4.删除节点
* 5.链表长度
*/
/**
* 1.头插 新节点从链表的头节点插入
*
* @param node
*/
public void addfirst(Node node)
if (head == null)
//当链表为空时
head = node;
tail=node;
return;
head.pre = node;
node.next = head;
head = node;
/**
* 尾插 新加入的节点从链表的尾节点加入
*
* @param node
*/
public void addtail(Node node)
if (tail == null)
//当链表为空时
head = node;
tail = node;
return;
//将插入节点赋值给tail节点---tail节点的下个节点指向插入节点,插入节点的上个节点指向tail节点的上个节点
tail.next = node;
node.pre = tail;
tail = node;//更新链表的尾部节点
public void del (Node node )
//更具id进行删除
Node temp = head;
//如果是空表直接返回
if (head == null)
System.out.println("当前为空链表");
return;
while (true)
if (temp.next == null)
break;//遍历到最后了
if (temp.key == node.key)
break;
temp = temp.next;
//删除操作,
// 当前节点的上个节点的下个节点指向当前节点的下个节点
// 当前节点的下个节点的上个节点指向当前节点的上个节点
//当删除节点是头节点或者尾节点时需要特殊处理
if (temp.key == head.key)
head=head.next;
if (head!=null)
head.pre=null;
else if (temp.key == tail.key )
tail = tail.pre;
if (tail!=null)
tail.next = null;
else
temp.pre.next=temp.next;
temp.next.pre=temp.pre;
public Node del_last()
if (tail==null)
return null;
Node temp=tail;
if(tail.pre!=null)
tail.pre.next=null;
tail=tail.pre;
return temp;
public int size()
int num=0;
Node temp=head;
if (head==null)
//列表为空
return 0;
while(true)
if (temp==null)
break;
num+=1;
temp=temp.next;
return num;
/**
* 打印链表
*/
public void print_list()
//遍历链表
Node tempnode = head;
while (true)
System.out.println(tempnode);
if (tempnode.next == null)
break;
tempnode = tempnode.next;
以上是关于LRU算法java实现的主要内容,如果未能解决你的问题,请参考以下文章