1 内存缓存淘汰机制
-
LRU (Least recently used) 最近最少使用,如果数据最近被访问过,那么将来被访问的几率也更高。
-
LFU (Least frequently used) 最不经常使用,如果一个数据在最近一段时间内使用次数很少,那么在将来一段时间内被使用的可能性也很小。
-
FIFO (Fist in first out) 先进先出, 如果一个数据最先进入缓存中,则应该最早淘汰掉。
LRU算法示意图:
- 新数据插入到链表头部
- 当缓存命中(即缓存数据被访问),数据要移到表头
- 当链表满的时候,将链表尾部的数据丢弃
2 实现自己的单链表
package test;
//单链表
public class LinkedList<T> {
Node list;
int size; //链表有多少个节点
public LinkedList() {
size = 0;
}
//添加节点
//在头部添加节点
public void put(T data) {
Node head = list;
Node curNode = new Node(data, list);
list = curNode;
size++;
}
//在链表的index 位置插入一个新的数据data
public void put(int index, T data) {
checkPositionIndex(index);
Node cur = list;
Node head = list;
for (int i = 0; i < index; i++) {
head = cur;
cur = cur.next;
}
Node node = new Node(data, cur);
head.next = node;
size++;
}
//删除节点
//删除头部节点
public T remove() {
if (list != null) {
Node node = list;
list = list.next;
node.next = null; // GC 回收
size--;
return node.data;
}
return null;
}
public T remove(int index) {
checkPositionIndex(index);
Node head = list;
Node cur = list;
for (int i = 0; i < index; i++) {
head = cur;
cur = cur.next;
}
head.next = cur.next;
cur.next = null;//GC
return cur.data;
}
public T removeLast() {
if (list != null) {
Node node = list;
Node cur = list;
while (cur.next != null) {
node = cur;
cur = cur.next;
}
node.next = null;
size--;
return cur.data;
}
return null;
}
//修改节点
public void set(int index, T newData) {
checkPositionIndex(index);
Node head = list;
for (int i = 0; i < index; i++) {
head = head.next;
}
head.data = newData;
}
//查询节点
//get 头部节点
public T get() {
Node node = list;
if (node != null) {
return node.data;
} else {
return null;
}
}
public T get(int index) {
checkPositionIndex(index);
Node node = list;
for (int i = 0; i < index; i++) {
node = node.next;
}
return node.data;
}
//检测index是否在链表范围以内
public void checkPositionIndex(int index) {
if (!(index >= 0 && index <= size)) {
throw new IndexOutOfBoundsException("index: " + index + ", size: " + size);
}
}
@Override
public String toString() {
Node node = list;
for (int i = 0; i < size; i++) {
System.out.print(node.data + " ");
// System.out.print(" ");
node = node.next;
}
System.out.println();
return super.toString();
}
//节点的信息
class Node {
T data;
Node next;
public Node(T data, Node node) {
this.data = data;
this.next = node;
}
}
public static void main(String[] args) {
LinkedList<Integer> list = new LinkedList<>();
for (int i = 0; i < 5; i++) {
list.put(i);
}
list.toString();
list.put(3, 3);
list.toString();
list.put(8);
list.toString();
System.out.println(list.get(2));
}
}
3 基于单链表手写实现LRU算法
package test;
public class LruLinkedList<T> extends LinkedList<T> {
int memory_size; // 用于限定内存空间大小,也就是缓存的大小
static final int DEFAULT_CAP = 5;
public LruLinkedList() {
this(DEFAULT_CAP);
}
public LruLinkedList(int default_memory_size) {
memory_size = default_memory_size;
}
//LRU添加节点
public void lruPut(T data) {
if (size >= memory_size) {
removeLast();
put(data);
} else {
put(data);
}
}
//LRU删除
public T lruRemove() {
return removeLast();
}
//LRU访问
public T lruGet(int index) {
checkPositionIndex(index);
Node node = list;
Node pre = list;
for (int i = 0; i < index; i++) {
pre = node;
node = node.next;
}
T resultData = node.data;
//将访问的节点移到表头
pre.next = node.next;
Node head = list;
node.next = head;
list = node;
return resultData;
}
public static void main(String[] args) {
LruLinkedList<Integer> lruLinkedList = new LruLinkedList<>(5);
for (int i = 0; i < 4; i++) {
lruLinkedList.lruPut(i);
}
lruLinkedList.toString();
System.out.println(lruLinkedList.lruGet(3));
lruLinkedList.toString();
lruLinkedList.lruPut(20);
lruLinkedList.toString();
lruLinkedList.lruPut(18);
lruLinkedList.toString();
}
}