缓存策略其实就是利用了空间换时间的设计思想。在内存空间相对充足、更要求执行速度的场景中使用。
维护一个有序的单链表,越靠近尾部的结点是越早之前访问的。当有一个新的数据被访问时,从链表头开始顺序遍历链表。
实现步骤分为两种情况:
代码部分在我之前写过的文章里进行增量修改。有兴趣的朋友请移步 ☞Java实现数据结构链表之单链表
添加最大长度属性和构造方法。
private Integer maxLength;
public SingleList(int maxLength) {
this.maxLength = maxLength;
}
添加实现LRU策略的方法。
/**
* 功能描述 : LRU
* @author Leo
* @date 2020/6/18 10:01 下午
* @param object
* @throw
* @return int
*/
public int singleListForLRU(T object) {
//添加之前判断链表中是否存在元素
int index = this.findNodeIndexByObject(object);
//如果存在,并且位置是0,不做删除和插入操作
if (index == 0) {
return this.length;
}
// 如果大于零,删除掉再插入
if (index > 0) {
this.delete(index);
}
//向链表头部插入元素
this.insert(object, 0);
//删除最后多余结点
if (maxLength!=null&&this.length > maxLength) {
this.delete(maxLength - 1);
}
//最后返回当前链表的长度
return this.length;
}
/**
* 功能描述 : 根据查找的元素返回结点位置 -1 表示查找的对象在链表中不存在
* @author Leo
* @date 2020/6/18 10:20 下午
* @param object
* @throw
* @return int
*/
public int findNodeIndexByObject(T object) {
int currentIndex = -1;
if (firstNode == null) {
return currentIndex;
} else {
Node<T> currentNode = this.firstNode;
int tempIndex = 0;
do {
if (currentNode.getObj() == object) {
currentIndex = tempIndex;
}
currentNode = currentNode.getNext();
tempIndex++;
} while (currentNode != null);
return currentIndex;
}
}
public static void main(String[] args){
SingleList<String> singleList = new SingleList<String>(6);
singleList.singleListForLRU("零");
System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString());
singleList.singleListForLRU("一");
System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString());
singleList.singleListForLRU("零");
System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString());
singleList.singleListForLRU("二");
System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString());
singleList.singleListForLRU("三");
System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString());
singleList.singleListForLRU("一");
System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString());
singleList.singleListForLRU("二");
System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString());
singleList.singleListForLRU("三");
System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString());
singleList.singleListForLRU("四");
System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString());
singleList.singleListForLRU("五");
System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString());
singleList.singleListForLRU("六");
System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString());
singleList.singleListForLRU("⑦");
System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString());
singleList.singleListForLRU("零");
System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString());
singleList.singleListForLRU("零");
System.out.println("当前链表长度: "+singleList.length+";当前链表数据: "+singleList.toString());
}
当前链表长度: 1;当前链表数据: SingleList={零}
当前链表长度: 2;当前链表数据: SingleList={一,零}
当前链表长度: 2;当前链表数据: SingleList={零,一}
当前链表长度: 3;当前链表数据: SingleList={二,零,一}
当前链表长度: 4;当前链表数据: SingleList={三,二,零,一}
当前链表长度: 4;当前链表数据: SingleList={一,三,二,零}
当前链表长度: 4;当前链表数据: SingleList={二,一,三,零}
当前链表长度: 4;当前链表数据: SingleList={三,二,一,零}
当前链表长度: 5;当前链表数据: SingleList={四,三,二,一,零}
当前链表长度: 6;当前链表数据: SingleList={五,四,三,二,一,零}
当前链表长度: 6;当前链表数据: SingleList={六,五,四,三,二,零}
当前链表长度: 6;当前链表数据: SingleList={⑦,六,五,四,三,零}
当前链表长度: 6;当前链表数据: SingleList={零,⑦,六,五,四,三}
当前链表长度: 6;当前链表数据: SingleList={零,⑦,六,五,四,三}
基于链表数据结构的实现思路,不管缓存有没有满,都需要遍历一遍链表,时间复杂度为O(n)。
使用其他数据机构可以将时间复杂度O(n)优化到O(1),比如引入散列表(Hash table) 来记录每个数据的位置。