基于哈希链表的方式实现的LRU算法,通过Hash表存储加快数据的访问效率
节点类
package demo.LRU2;
/**
* @author koala
* @ClassName Node
* @date 2019/9/17 09:24
* @Description
* @Version V1.0
*/
public class Node {
String key;
Object value;
/**
* 上一个节点
*/
Node preNode;
/**
* 下一个节点
*/
Node nextNode;
/**
* 构造方法
* @param key
* @param value
*/
Node(String key,Object value){
this.key = key;
this.value = value;
this.preNode = null;
this.nextNode = null;
}
@Override
public String toString() {
return super.toString();
}
}
双向链表类
这里的双向链表只存储头部节点和尾部节点;
package demo.LRU2;
/**
* @author koala
* @ClassName DoublyLinkedList
* @date 2019/9/17 10:09
* @Description 双向链表
* @Version V1.0
*/
public class DoublyLinkedList {
public Node head;
public Node tail;
DoublyLinkedList(){
this.head = null;
this.tail = null;
}
/**
* 移动到头部节点去
* @param node
*/
public void moveToHead(Node node){
if(node == null || node == head){
return ;
}
// 如果当前节点是尾节点;
if(tail == node){
// 把当前节点添加到头部去
addToHead(node);
// 移除尾部的节点
removeTail();
}else{
// 当前节点前后节点交换
Node curNextNode = node.nextNode;
curNextNode.preNode = node.preNode;
Node curPreNode = node.preNode;
curPreNode.nextNode = curNextNode;
// 节点交换
head.preNode = node;
node.nextNode = head;
node.preNode = null;
head = head.preNode;
}
}
/**
* 删除尾部节点
*/
public Node removeTail(){
if(tail == null){
return null;
}
/**
* 获取当前尾部节点;
*/
Node n = tail;
if(head == tail){
head = null;
tail = null;
}else{
// 当前尾部节点的上一个节点就为新的尾节点
tail = n.preNode;
// 尾节点的下一个节点置空
tail.nextNode = null;
}
//
return n;
}
/**
*
* @param node
*/
public void addToHead(Node node){
if(node == null){
return ;
}
/**
* 如果没有上一级节点,证明是第一个节点,那假定前一个和后一个节点都是当前节点
*/
if(head == null){
head = node;
tail = node;
}else{
// 把当前节点放到链表最前面
node.nextNode = head;
head.preNode = node;
// 重新指定头部节点
head = node;
}
}
@Override
public String toString() {
return super.toString();
}
}
缓存类
package demo.LRU2;
import java.util.HashMap;
import java.util.Map;
/**
* @author koala
* @ClassName Cache
* @date 2019/9/17 09:23
* @Description
* 最近最少使用算法 。 最近最少使用的元素,在接下来一段时间内,被访问的概率也很低。
* * 即最近被使用的元素,在接下来一段时间内,被访问概率较高。
* * <p>
* * 用链表的结构:
* * 链表头部表示最后实现的数据,越靠近最后表示没有使用的数据;
* * <p>
* 插入一个元素,如果没有达到阈值,就放到最前面;如果超过最大的阈值,移除链表尾部的数据;
* *
* * 访问一个元素,如果存在,则将该元素放到最前面;如果不存在;则返回空
* * <p>
*
* * 为提高效率,采用hash表存储数据
* @Version V1.0
*/
public class Cache {
private HashMap<String, Node> map;
/**
* 双向链接实现LRU顺序
*/
private DoublyLinkedList list;
/**
* 当前节点的大小
*/
private int size = 0;
/**
* 最大容量
*/
private int capacity = 10;
/**
* 初始化、并且赋值最大的容量
* @param capacity
*/
Cache(int capacity){
this.list = new DoublyLinkedList();
this.map = new HashMap<>();
this.capacity = capacity;
}
Cache(){
this.list = new DoublyLinkedList();
this.map = new HashMap<>();
}
/**
* 插入一个数据
* @param key
*/
public void put(String key,Object value){
if(!map.containsKey(key)){
Node n = new Node(key,value);
map.put(key,n);
list.addToHead(n);
// 如果超过最大的容量、移除最后一个数据
if(map.size() > capacity){
Node node = list.removeTail();
map.remove(node.key);
}
}else{
// 如果存在,就覆盖value的值
Node node = map.get(key);
node.value = value;
list.moveToHead(node);
}
}
/**
* 根据键获取值
* @param key
* @return
*/
public Object get(String key){
if(map.containsKey(key)){
Node node = map.get(key);
list.moveToHead(node);
return node.value;
}else{
return null;
}
}
public DoublyLinkedList getAllList(){
return list;
}
public Map getAllDataMap(){
return this.map;
}
}
测试类
package demo.LRU2;
/**
* @author koala
* @ClassName test
* @date 2019/9/17 10:55
* @Description
* @Version V1.0
*/
public class test {
public static void main(String[] args) {
Cache cache = new Cache(5);
cache.put("1","hello1");
cache.put("2","hello2");
cache.put("3","hello3");
cache.put("4","hello4");
cache.put("5","hello5");
cache.put("6","hello6");
cache.get("3");
for (Object map:cache.getAllDataMap().entrySet()) {
System.out.println(map.toString());
}
DoublyLinkedList doublyLinkedList = cache.getAllList();
System.out.println(doublyLinkedList.head.preNode);
System.out.println(doublyLinkedList.tail);
System.out.println("头部节点, key:"+doublyLinkedList.head.key+";" +
"头部节点上级节点:"+doublyLinkedList.head.preNode+"" +
"头部节点下级节点:"+doublyLinkedList.head.nextNode.key);
System.out.println("尾部节点, key:"+doublyLinkedList.tail.key+";" +
"尾部节点上级节点:"+doublyLinkedList.tail.preNode.key+"" +
"尾部节点下级节点:"+doublyLinkedList.tail.nextNode);
}
}