内存缓存淘汰机制
- FIFO(First In First Out,先进先出)
- LFU(Least Frequently Used,最不经常使用)
- LRU(Least Recently Used,最近最少使用)
LFU是从整个使用时间内判断使用次数最少的算法,而LRU是从最近一段时间内来判断使用次数最少的算法
LRU算法
- 新数据插入到链表的头部
- 当缓存命中(即缓存数据被访问),数据要移动到表头
- 当链表满的时候,将链表尾部数据丢弃
自定义单链表和继承自自定义单链表的Lru算法链表
1.自定义单链表类MyLinkedList.java
package com.tangkun.lru;
/**
* 自定义单链表
* */
public class MyLinkedList<T> {
//头结点的指针
public Node<T> node;
//链表的结点总数量
public int size;
public MyLinkedList() {
}
/**
* 新增 指定索引位置新增
*/
public void put(int index, T data) {
checkPositionIndex(index);
//插入结点位置的前一个结点
Node<T> prev = node;
//插入结点位置原来那个结点,新结点插入后,这个结点就在新结点后面
Node<T> cur = node;
//遍历出插入位置上一个结点和原来的结点
for (int i = 0; i < index; i++) {
prev = cur;
cur = cur.next;
}
//构建出插入索引位置的新结点,将上面遍历出来的原来结点cur作为新结点的next指针的值
Node<T> newNode = new Node<>(data, cur);
//将插入位置上一个结点的next指针指向新插入的结点
prev.next = newNode;
//链表长度加1
size++;
}
//新增到头部
public void putFirst(T data) {
//插入结点位置原来那个结点,新结点插入后,这个结点就在新结点后面
Node<T> cur = node;
Node<T> newNode = new Node<>(data, cur);
//将插入到头部的结点赋值为整个链表的头结点
node = newNode;
size++;
}
/**
* 删除
*/
public void remove(int index) {
checkPositionIndex(index);
//删除结点位置的前一个结点
Node<T> prev = node;
//删除结点位置原来那个结点
Node<T> cur = node;
//遍历出删除位置上一个结点和原来的结点
for (int i = 0; i < index; i++) {
prev = cur;
cur = cur.next;
}
prev.next = cur.next;
cur.next = null;
//链表长度减1
size--;
}
//删除最后一个结点
public void removeLast() {
//删除结点位置的前一个结点
Node<T> prev = node;
//删除结点位置原来那个结点
Node<T> cur = node;
//遍历出删除位置上一个结点和原来的结点
for (int i = 0; i < size; i++) {
prev = cur;
cur = cur.next;
}
prev.next = null;
//链表长度减1
size--;
}
/**
* 修改
*/
public T set(int index, T data) {
checkPositionIndex(index);
//修改结点位置原来那个结点
Node<T> cur = node;
//遍历出修改位置的结点
for (int i = 0; i < index; i++) {
cur = cur.next;
}
cur.data = data;
return cur.data;
}
/**
* 查询
*/
public T get(int index) {
checkPositionIndex(index);
//查询结点位置原来那个结点
Node<T> cur = node;
//遍历出查询位置的结点
for (int i = 0; i < index; i++) {
cur = cur.next;
}
return cur.data;
}
/**
* 检查index是否越界
*/
public void checkPositionIndex(int index) {
if (!(index >= 0 && index <= size)) {
throw new IndexOutOfBoundsException("index:" + index + "|size:" + size);
}
}
@Override
public String toString() {
//打印出来所有结点中的数据域
Node<T> cur = node;
for (int i = 0; i < size; i++) {
System.out.println(cur.data + " ");
cur = cur.next;
}
return "";
}
static class Node<T> {
T data;
Node<T> next;
Node(T data, Node<T> next) {
this.data = data;
this.next = next;
}
}
public static void main(String[] args) {
MyLinkedList<Integer> myLinkedList = new MyLinkedList<>();
myLinkedList.putFirst(3);
myLinkedList.putFirst(2);
myLinkedList.putFirst(1);
System.out.println("添加结点后打印:" + myLinkedList.toString() + "\n");
myLinkedList.put(2, 0);
System.out.println("在索引为2的位置,添加结点0,然后打印:" + myLinkedList.toString() + "\n");
myLinkedList.remove(1);
System.out.println("删除索引为1的结点后打印:" + myLinkedList.toString() + "\n");
myLinkedList.set(1, 8);
System.out.println("更改索引1的值为8,然后打印:" + myLinkedList.toString() + "\n");
myLinkedList.get(1);
System.out.println("查询索引1的值:" + myLinkedList.get(1) + "\n");
}
}
2.自定义Lru算法单链表LruLinkedList.java
package com.tangkun.lru;
/**
* Lru算法单链表
* */
public class LruLinkedList<T> extends MyLinkedList<T> {
//自定义缓存容量大小
public int memorySize;
//缓存默认容量大小
public static final int DEFAULT_CAPACITY = 5;
public LruLinkedList() {
this(DEFAULT_CAPACITY);
}
public LruLinkedList(int capacity) {
memorySize = capacity;
}
/**
* Lru新增
* 新数据插入到链表的头部
*/
public void lruPutFirst(T data) {
//判断当前缓存占用大小是否等于最大缓存容量,如果小于,则memorySize加1;若大于等于,则memorySize=MAX_CAPACITY,同时移除链表中最后一个结点
if (size < memorySize) {
} else {
//移除最后一个结点
removeLast();
}
//新增结点到头部
putFirst(data);
}
/**
* Lru 查询
* 当缓存命中(即缓存数据被访问),数据要移动到表头
*/
public T lruGet(int index) {
checkPositionIndex(index);
//当前索引index前一个结点
Node<T> prev = node;
//当前索引index那个结点
Node<T> cur = node;
for (int i = 0; i < index; i++) {
prev = cur;
cur = cur.next;
}
//此时需要将该结点从链表中删除,同时将当前结点移动到链表的头部
prev.next = cur.next;
//注意,这里将查询的结点拿出来后,链表长度要减1
size--;
//将查询的结点添加到链表头部
putFirst(cur.data);
return cur.data;
}
public static void main(String[] args) {
LruLinkedList<Integer> lruLinkedList = new LruLinkedList<>(3);
lruLinkedList.lruPutFirst(1);
lruLinkedList.lruPutFirst(2);
lruLinkedList.lruPutFirst(3);
lruLinkedList.lruPutFirst(4);
System.out.println("自定义lru集合长度为3,然后往lru缓存中添加结点,打印出lur集合中数据:" + lruLinkedList.toString() + "\n");
lruLinkedList.lruGet(2);
System.out.println("查询lru集合中索引为2的结点,然后打印出查询后的集合中元素的排序:" + lruLinkedList.toString());
}
}